diff -urN linux-2.4.25/CREDITS linux-2.4.26/CREDITS --- linux-2.4.25/CREDITS 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/CREDITS 2004-04-14 06:05:21.000000000 -0700 @@ -3386,9 +3386,9 @@ W: http://www.yoshifuji.org/~hideaki/ P: 1024D/E0620EEA 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA D: IPv6 and other networking related stuff -D: USAGI/WIDE Project, The University of Tokyo -S: Green House #102, 1-15-5, Nishikata, -S: Bunkyo, Tokyo 113-0024 +D: USAGI/WIDE Project, Keio University +S: Jeunet Palace Kawasaki #1-201, 10-2, Furukawa-cho, Saiwai-ku +S: Kawasaki, Kanagawa 212-0025 S: Japan N: Eric Youngdale diff -urN linux-2.4.25/Documentation/Configure.help linux-2.4.26/Documentation/Configure.help --- linux-2.4.25/Documentation/Configure.help 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/Documentation/Configure.help 2004-04-14 06:05:24.000000000 -0700 @@ -1159,6 +1159,14 @@ This effect can be also invoked by calling "idex=ata66" If unsure, say N. +ATI IXP chipset IDE support +CONFIG_BLK_DEV_ATIIXP + This driver adds explicit support for ATI IXP chipset. + This allows the kernel to change PIO, DMA and UDMA speeds + and to configure the chip to optimum performance. + + Say Y here if you have an ATI IXP chipset IDE controller. + CMD64X/CMD680 chipset support CONFIG_BLK_DEV_CMD64X Say Y here if you have an IDE controller which uses any of these @@ -2085,6 +2093,40 @@ If you choose to compile this as a module, the module will be called hptraid.o. +CMD/Silicon Image Medley Software RAID +CONFIG_BLK_DEV_ATARAID_MEDLEY + Say Y or M if you have a Silicon Image 3112 SATA RAID controller, + a CMD680 based controller, or another IDE RAID controller that uses + CMD's Medley software RAID, and want Linux to use the software RAID + feature of this card. This driver uses /dev/ataraid/dXpY (X and Y + numbers) as device names. + + This driver currently only supports RAID0 (striped) mode, so if you + are using RAID1 (mirroring) this will not work for you. In that + case, you may want to try the Silicon Image Medley Software RAID + driver (below). + + Support for mirroring is planned in the future. + + If you choose to compile this as a module, the module will be called + medley.o. + +Silicon Image Medley Software RAID (old driver) +CONFIG_BLK_DEV_ATARAID_SII + Say Y or M if you have a Silicon Image SATARaid controller + and want Linux to use the softwareraid feature of this card. + This driver uses /dev/ataraid/dXpY (X and Y numbers) as device + names. + + This driver does not reliably detect all Medley RAID sets, and could + be dangerous if you have a striped set with disks of different size. + + You should use the new Medley RAID driver (above), unless you use + RAID1 (mirroring), which the new driver does not yet support. + + If you choose to compile this as a module, the module will be called + silraid.o. + Support for Acer PICA 1 chipset CONFIG_ACER_PICA_61 This is a machine with a R4400 133/150 MHz CPU. To compile a Linux @@ -6206,17 +6248,6 @@ If in doubt, say N. -SCTP: Use old checksum (Adler-32) -CONFIG_SCTP_ADLER32 - RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP. - This has been deprecated and replaced by an algorithm now referred - to as crc32c. - - If you say Y, this will use the Adler-32 algorithm, this might be - useful for interoperation with downlevel peers. - - If unsure, say N. - SCTP: Debug messages CONFIG_SCTP_DBG_MSG If you say Y, this will enable verbose debugging messages. @@ -6234,6 +6265,29 @@ If unsure, say N +#choice +SCTP: HMAC algorithm +CONFIG_SCTP_HMAC_NONE + Choose an HMAC algorithm to be used during association establishment. + It can be one of SHA1, MD5 or NONE. It is advised to use either HMAC-MD5 + or HMAC-SHA1. + See configuration for Cryptographic API and enable these algorithms + to make usable by SCTP. + +SCTP: SHA1 HMAC algorithm +CONFIG_SCTP_HMAC_SHA1 + Enable the use of HMAC-SHA1 during association establishment. It + is advised to use either HMAC-MD5 or HMAC-SHA1. + See configuration for Cryptographic API and enable these algorithms + to make usable by SCTP. + +SCTP: MD5 HMAC algorithm +config SCTP_HMAC_MD5 + Enable the use of HMAC-MD5 during association establishment. It is + advised to use either HMAC-MD5 or HMAC-SHA1. + See configuration for Cryptographic API and enable these algorithms + to make usable by SCTP. + Kernel httpd acceleration CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web @@ -7001,8 +7055,11 @@ Packet socket: mmapped IO CONFIG_PACKET_MMAP - If you say Y here, the Packet protocol driver will use an IO - mechanism that results in faster communication. + If you say Y here, the Packet protocol driver can use a faster and + more efficient capture method. This feature also allows bigger + receive buffers. To take advantage of this method who have to use + a libpcap library that supports it. For more info see + . If unsure, say N. @@ -10237,6 +10294,19 @@ say M here and read . The module will be called airo_cs.o. +Atmel at76c502/at76c504 PCMCIA cards +CONFIG_PCMCIA_ATMEL + A driver for PCMCIA 802.11 wireless cards based on the + Atmel fast-vnet chips. This driver supports standard + Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz + Aviator/Raytheon 2.4MHz wireless support CONFIG_PCMCIA_RAYCS Say Y here if you intend to attach an Aviator/Raytheon PCMCIA @@ -10770,6 +10840,14 @@ whenever you want). If you want to compile it as a module, say M here and read . +Network delay simualtor +CONFIG_NET_SCH_DELAY + Say Y if you want to delay packets by a fixed amount of + time. This is often useful to simulate network delay when + testing applications or protocols. + + This code is also available as a module called sch_delay.o + Ingress Qdisc CONFIG_NET_SCH_INGRESS If you say Y here, you will be able to police incoming bandwidth @@ -12358,6 +12436,16 @@ . The module will be called b44. +nForce Ethernet support (EXPERIMENTAL) +CONFIG_FORCEDETH + If you have a network (Ethernet) controller of this type, say Y and + read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here and read + . The module will be + called forcedeth.o. + CS89x0 support (Daynaport CS and LC cards) CONFIG_CS89x0 Support for CS89x0 chipset based Ethernet cards. If you have a @@ -19919,14 +20007,6 @@ of verbosity. Saying Y enables these statements. This will increase your kernel size by around 50K. -ACPI Relaxed AML Checking -CONFIG_ACPI_RELAXED_AML - If you say `Y' here, the ACPI interpreter will relax its checking - for valid AML and will ignore some AML mistakes, such as off-by-one - errors in region sizes. Some laptops may require this option. In - particular, many Toshiba laptops require this for correct operation - of the AC module. - ACPI Button CONFIG_ACPI_BUTTON This driver registers for events based on buttons, such as the @@ -23541,7 +23621,7 @@ If you have the BSC Oktagon SCSI disk controller for the Amiga, say Y to this question. If you're in doubt about whether you have one, see the picture at - . + . Atari native SCSI support CONFIG_ATARI_SCSI @@ -28701,6 +28781,13 @@ The CAST6 encryption algorithm (synonymous with CAST-256) is described in RFC2612. +CONFIG_CRYPTO_ARC4 + ARC4 cipher algorithm. + + This is a stream cipher using keys ranging from 8 bits to 2048 + bits in length. ARC4 is commonly used in protocols such as WEP + and SSL. + CONFIG_CRYPTO_DEFLATE This is the Deflate algorithm (RFC1951), specified for use in IPSec with the IPCOMP protocol (RFC3173, RFC2394). diff -urN linux-2.4.25/Documentation/crypto/api-intro.txt linux-2.4.26/Documentation/crypto/api-intro.txt --- linux-2.4.25/Documentation/crypto/api-intro.txt 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/Documentation/crypto/api-intro.txt 2004-04-14 06:05:24.000000000 -0700 @@ -185,6 +185,8 @@ Matthew Skala (Twofish) Dag Arne Osvik (Serpent) Brian Gladman (AES) + Kartikey Mahendra Bhatt (CAST6) + Jon Oberheide (ARC4) SHA1 algorithm contributors: Jean-Francois Dive diff -urN linux-2.4.25/Documentation/kernel-parameters.txt linux-2.4.26/Documentation/kernel-parameters.txt --- linux-2.4.25/Documentation/kernel-parameters.txt 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/Documentation/kernel-parameters.txt 2004-04-14 06:05:24.000000000 -0700 @@ -73,16 +73,21 @@ off Disable ACPI ht Limit ACPI to boot-time LAPIC enumeration for HT, disabling the run-time AML interpreter. + strict Be less tolerant of platforms that are not + strictly ACPI specification compliant. - acpi_pic_sci= [HW,ACPI] ACPI System Conrol Interrupt trigger mode - level Force PIC-mode SCI to Level Trigger (default) - edge Force PIC-mode SCI to Edge Trigger + acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode + Format: { level | edge | high | low } acpi_irq_balance ACPI will balance active IRQs acpi_irq_nobalance ACPI will not move active IRQs acpi_irq_pci= If irq_balance, Clear listed IRQs for use by PCI acpi_irq_isa= If irq_balance, Mark listed IRQs used by ISA + acpi_osi= [HW,ACPI] empty param disables _OSI + + acpi_serialize [HW,ACPI] force serialization of AML methods + ad1816= [HW,SOUND] ad1848= [HW,SOUND] diff -urN linux-2.4.25/Documentation/networking/bonding.txt linux-2.4.26/Documentation/networking/bonding.txt --- linux-2.4.25/Documentation/networking/bonding.txt 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/Documentation/networking/bonding.txt 2004-04-14 06:05:25.000000000 -0700 @@ -21,7 +21,7 @@ Table of Contents ================= - + Installation Bond Configuration Module Parameters @@ -31,6 +31,7 @@ Frequently Asked Questions High Availability Promiscuous Sniffing notes +8021q VLAN support Limitations Resources and Links @@ -66,7 +67,7 @@ /usr/include/linux. To install ifenslave.c, do: - # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave + # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave # cp ifenslave /sbin/ifenslave @@ -74,10 +75,10 @@ ================== You will need to add at least the following line to /etc/modules.conf -so the bonding driver will automatically load when the bond0 interface is -configured. Refer to the modules.conf manual page for specific modules.conf -syntax details. The Module Parameters section of this document describes each -bonding driver parameter. +so the bonding driver will automatically load when the bond0 interface is +configured. Refer to the modules.conf manual page for specific modules.conf +syntax details. The Module Parameters section of this document describes each +bonding driver parameter. alias bond0 bonding @@ -113,7 +114,7 @@ network interface be a slave of bond1. Restart the networking subsystem or just bring up the bonding device if your -administration tools allow it. Otherwise, reboot. On Red Hat distros you can +administration tools allow it. Otherwise, reboot. On Red Hat distros you can issue `ifup bond0' or `/etc/rc.d/init.d/network restart'. If the administration tools of your distribution do not support @@ -128,30 +129,26 @@ (use appropriate values for your network above) -You can then create a script containing these commands and place it in the +You can then create a script containing these commands and place it in the appropriate rc directory. If you specifically need all network drivers loaded before the bonding driver, -adding the following line to modules.conf will cause the network driver for +adding the following line to modules.conf will cause the network driver for eth0 and eth1 to be loaded before the bonding driver. probeall bond0 eth0 eth1 bonding -Be careful not to reference bond0 itself at the end of the line, or modprobe +Be careful not to reference bond0 itself at the end of the line, or modprobe will die in an endless recursive loop. -To have device characteristics (such as MTU size) propagate to slave devices, -set the bond characteristics before enslaving the device. The characteristics -are propagated during the enslave process. - -If running SNMP agents, the bonding driver should be loaded before any network -drivers participating in a bond. This requirement is due to the the interface -index (ipAdEntIfIndex) being associated to the first interface found with a -given IP address. That is, there is only one ipAdEntIfIndex for each IP -address. For example, if eth0 and eth1 are slaves of bond0 and the driver for -eth0 is loaded before the bonding driver, the interface for the IP address -will be associated with the eth0 interface. This configuration is shown below, -the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 +If running SNMP agents, the bonding driver should be loaded before any network +drivers participating in a bond. This requirement is due to the the interface +index (ipAdEntIfIndex) being associated to the first interface found with a +given IP address. That is, there is only one ipAdEntIfIndex for each IP +address. For example, if eth0 and eth1 are slaves of bond0 and the driver for +eth0 is loaded before the bonding driver, the interface for the IP address +will be associated with the eth0 interface. This configuration is shown below, +the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 in the ifDescr table (ifDescr.2). interfaces.ifTable.ifEntry.ifDescr.1 = lo @@ -189,10 +186,10 @@ Module Parameters ================= -Optional parameters for the bonding driver can be supplied as command line -arguments to the insmod command. Typically, these parameters are specified in -the file /etc/modules.conf (see the manual page for modules.conf). The -available bonding driver parameters are listed below. If a parameter is not +Optional parameters for the bonding driver can be supplied as command line +arguments to the insmod command. Typically, these parameters are specified in +the file /etc/modules.conf (see the manual page for modules.conf). The +available bonding driver parameters are listed below. If a parameter is not specified the default value is used. When initially configuring a bond, it is recommended "tail -f /var/log/messages" be run in a separate window to watch for bonding driver error messages. @@ -202,19 +199,19 @@ during link failures. arp_interval - - Specifies the ARP monitoring frequency in milli-seconds. - If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the - switch should be configured in a mode that evenly distributes packets - across all links - such as round-robin. If the switch is configured to - distribute the packets in an XOR fashion, all replies from the ARP - targets will be received on the same link which could cause the other + + Specifies the ARP monitoring frequency in milli-seconds. + If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the + switch should be configured in a mode that evenly distributes packets + across all links - such as round-robin. If the switch is configured to + distribute the packets in an XOR fashion, all replies from the ARP + targets will be received on the same link which could cause the other team members to fail. ARP monitoring should not be used in conjunction - with miimon. A value of 0 disables ARP monitoring. The default value + with miimon. A value of 0 disables ARP monitoring. The default value is 0. - + arp_ip_target - + Specifies the ip addresses to use when arp_interval is > 0. These are the targets of the ARP request sent to determine the health of the link to the targets. Specify these values in ddd.ddd.ddd.ddd @@ -223,8 +220,8 @@ maximum number of targets that can be specified is set at 16. downdelay - - Specifies the delay time in milli-seconds to disable a link after a + + Specifies the delay time in milli-seconds to disable a link after a link failure has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. @@ -247,7 +244,7 @@ and bond2 will be created. The default value is 1. miimon - + Specifies the frequency in milli-seconds that MII link monitoring will occur. A value of zero disables MII link monitoring. A value of 100 is a good starting point. See High Availability section for @@ -258,7 +255,7 @@ Specifies one of the bonding policies. The default is round-robin (balance-rr). Possible values are (you can use either the text or numeric option): - + balance-rr or 0 Round-robin policy: Transmit in a sequential order @@ -273,7 +270,7 @@ externally visible on only one port (network adapter) to avoid confusing the switch. This mode provides fault tolerance. - + balance-xor or 2 XOR policy: Transmit based on [(source MAC address @@ -293,7 +290,7 @@ groups that share the same speed and duplex settings. Transmits and receives on all slaves in the active aggregator. - + Pre-requisites: 1. Ethtool support in the base drivers for retrieving the @@ -317,7 +314,7 @@ Ethtool support in the base drivers for retrieving the speed of each slave. - balance-alb or 6 + balance-alb or 6 Adaptive load balancing: includes balance-tlb + receive load balancing (rlb) for IPV4 traffic and does not require @@ -327,7 +324,7 @@ overwrites the src hw address with the unique hw address of one of the slaves in the bond such that different clients use different hw addresses for the server. - + Receive traffic from connections created by the server is also balanced. When the server sends an ARP Request the bonding driver copies and saves the client's IP information @@ -363,25 +360,11 @@ 2. Base driver support for setting the hw address of a device also when it is open. This is required so that there will always be one slave in the team using the bond hw - address (the current_slave) while having a unique hw - address for each slave in the bond. If the current_slave - fails it's hw address is swapped with the new current_slave + address (the curr_active_slave) while having a unique hw + address for each slave in the bond. If the curr_active_slave + fails it's hw address is swapped with the new curr_active_slave that was chosen. -multicast - - Option specifying the mode of operation for multicast support. - Possible values are: - - disabled or 0 - Disabled (no multicast support) - - active or 1 - Enabled on active slave only, useful in active-backup mode - - all or 2 - Enabled on all slaves, this is the default - primary A string (eth0, eth2, etc) to equate to a primary device. If this @@ -397,11 +380,11 @@ primary is only valid in active-backup mode. updelay - - Specifies the delay time in milli-seconds to enable a link after a + + Specifies the delay time in milli-seconds to enable a link after a link up status has been detected. This should be a multiple of miimon value, otherwise the value will be rounded. The default value is 0. - + use_carrier Specifies whether or not miimon should use MII or ETHTOOL @@ -529,20 +512,20 @@ ---------------------------- The bonding driver information files reside in the /proc/net/bonding directory. -Sample contents of /proc/net/bonding/bond0 after the driver is loaded with +Sample contents of /proc/net/bonding/bond0 after the driver is loaded with parameters of mode=0 and miimon=1000 is shown below. - + Bonding Mode: load balancing (round-robin) Currently Active Slave: eth0 MII Status: up MII Polling Interval (ms): 1000 Up Delay (ms): 0 Down Delay (ms): 0 - + Slave Interface: eth1 MII Status: up Link Failure Count: 1 - + Slave Interface: eth0 MII Status: up Link Failure Count: 1 @@ -550,34 +533,34 @@ 2) Network verification ----------------------- The network configuration can be verified using the ifconfig command. In -the example below, the bond0 interface is the master (MASTER) while eth0 and -eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address +the example below, the bond0 interface is the master (MASTER) while eth0 and +eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address (HWaddr) as bond0 for all modes except TLB and ALB that require a unique MAC address for each slave. [root]# /sbin/ifconfig -bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +bond0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING MASTER MULTICAST MTU:1500 Metric:1 RX packets:7224794 errors:0 dropped:0 overruns:0 frame:0 TX packets:3286647 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:0 + collisions:0 txqueuelen:0 -eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth0 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3573025 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643167 errors:1 dropped:0 overruns:1 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:10 Base address:0x1080 + collisions:0 txqueuelen:100 + Interrupt:10 Base address:0x1080 -eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 +eth1 Link encap:Ethernet HWaddr 00:C0:F0:1F:37:B4 inet addr:XXX.XXX.XXX.YYY Bcast:XXX.XXX.XXX.255 Mask:255.255.252.0 UP BROADCAST RUNNING SLAVE MULTICAST MTU:1500 Metric:1 RX packets:3651769 errors:0 dropped:0 overruns:0 frame:0 TX packets:1643480 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - Interrupt:9 Base address:0x1400 + collisions:0 txqueuelen:100 + Interrupt:9 Base address:0x1400 Frequently Asked Questions @@ -605,9 +588,9 @@ 5. What happens when a slave link dies? - If your ethernet cards support MII or ETHTOOL link status monitoring - and the MII monitoring has been enabled in the driver (see description - of module parameters), there will be no adverse consequences. This + If your ethernet cards support MII or ETHTOOL link status monitoring + and the MII monitoring has been enabled in the driver (see description + of module parameters), there will be no adverse consequences. This release of the bonding driver knows how to get the MII information and enables or disables its slaves according to their link status. See section on High Availability for additional information. @@ -615,15 +598,15 @@ For ethernet cards not supporting MII status, the arp_interval and arp_ip_target parameters must be specified for bonding to work correctly. If packets have not been sent or received during the - specified arp_interval durration, an ARP request is sent to the + specified arp_interval duration, an ARP request is sent to the targets to generate send and receive traffic. If after this interval, either the successful send and/or receive count has not incremented, the next slave in the sequence will become the active slave. If neither mii_monitor and arp_interval is configured, the bonding - driver will not handle this situation very well. The driver will - continue to send packets but some packets will be lost. Retransmits + driver will not handle this situation very well. The driver will + continue to send packets but some packets will be lost. Retransmits will cause serious degradation of performance (in the case when one of two slave links fails, 50% packets will be lost, which is a serious problem for both TCP and UDP). @@ -636,9 +619,9 @@ 7. Which switches/systems does it work with? - In round-robin and XOR mode, it works with systems that support + In round-robin and XOR mode, it works with systems that support trunking: - + * Many Cisco switches and routers (look for EtherChannel support). * SunTrunking software. * Alteon AceDirector switches / WebOS (use Trunks). @@ -646,7 +629,7 @@ models (450) can define trunks between ports on different physical units. * Linux bonding, of course ! - + In 802.3ad mode, it works with with systems that support IEEE 802.3ad Dynamic Link Aggregation: @@ -667,32 +650,24 @@ is then passed to all following slaves and remains persistent (even if the the first slave is removed) until the bonding device is brought down or reconfigured. - + If you wish to change the MAC address, you can set it with ifconfig: # ifconfig bond0 hw ether 00:11:22:33:44:55 The MAC address can be also changed by bringing down/up the device and then changing its slaves (or their order): - + # ifconfig bond0 down ; modprobe -r bonding # ifconfig bond0 .... up # ifenslave bond0 eth... This method will automatically take the address from the next slave that will be added. - - To restore your slaves' MAC addresses, you need to detach them - from the bond (`ifenslave -d bond0 eth0'), set them down - (`ifconfig eth0 down'), unload the drivers (`rmmod 3c59x', for - example) and reload them to get the MAC addresses from their - eeproms. If the driver is shared by several devices, you need - to turn them all down. Another solution is to look for the MAC - address at boot time (dmesg or tail /var/log/messages) and to - reset it by hand with ifconfig : - # ifconfig eth0 down - # ifconfig eth0 hw ether 00:20:40:60:80:A0 + To restore your slaves' MAC addresses, you need to detach them + from the bond (`ifenslave -d bond0 eth0'). The bonding driver will then + restore the MAC addresses that the slaves had before they were enslaved. 9. Which transmit polices can be used? @@ -729,27 +704,27 @@ ================= To implement high availability using the bonding driver, the driver needs to be -compiled as a module, because currently it is the only way to pass parameters +compiled as a module, because currently it is the only way to pass parameters to the driver. This may change in the future. -High availability is achieved by using MII or ETHTOOL status reporting. You -need to verify that all your interfaces support MII or ETHTOOL link status -reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and -yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting -is available for interface eth0, type "ethtool eth0" and the "Link detected:" -line should contain the correct link status. If your system has an interface -that does not support MII or ETHTOOL status reporting, a failure of its link -will not be detected! A message indicating MII and ETHTOOL is not supported by -a network driver is logged when the bonding driver is loaded with a non-zero +High availability is achieved by using MII or ETHTOOL status reporting. You +need to verify that all your interfaces support MII or ETHTOOL link status +reporting. On Linux kernel 2.2.17, all the 100 Mbps capable drivers and +yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting +is available for interface eth0, type "ethtool eth0" and the "Link detected:" +line should contain the correct link status. If your system has an interface +that does not support MII or ETHTOOL status reporting, a failure of its link +will not be detected! A message indicating MII and ETHTOOL is not supported by +a network driver is logged when the bonding driver is loaded with a non-zero miimon value. The bonding driver can regularly check all its slaves links using the ETHTOOL -IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The -check interval is specified by the module argument "miimon" (MII monitoring). -It takes an integer that represents the checking time in milliseconds. It -should not come to close to (1000/HZ) (10 milli-seconds on i386) because it -may then reduce the system interactivity. A value of 100 seems to be a good -starting point. It means that a dead link will be detected at most 100 +IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The +check interval is specified by the module argument "miimon" (MII monitoring). +It takes an integer that represents the checking time in milliseconds. It +should not come to close to (1000/HZ) (10 milli-seconds on i386) because it +may then reduce the system interactivity. A value of 100 seems to be a good +starting point. It means that a dead link will be detected at most 100 milli-seconds after it goes down. Example: @@ -761,7 +736,7 @@ alias bond0 bonding options bond0 miimon=100 -There are currently two policies for high availability. They are dependent on +There are currently two policies for high availability. They are dependent on whether: a) hosts are connected to a single host or switch that support trunking @@ -811,7 +786,7 @@ # ifenslave bond0 eth0 eth1 -2) High Availability on two or more switches (or a single switch without +2) High Availability on two or more switches (or a single switch without trunking support) --------------------------------------------------------------------------- This mode is more problematic because it relies on the fact that there @@ -857,7 +832,7 @@ In this configuration, there is an ISL - Inter Switch Link (could be a trunk), several servers (host1, host2 ...) attached to both switches each, and one or -more ports to the outside world (port3...). One an only one slave on each host +more ports to the outside world (port3...). One and only one slave on each host is active at a time, while all links are still monitored (the system can detect a failure of active and backup links). @@ -870,10 +845,10 @@ connected to one switch and host2's to the other. Such system will survive a failure of a single host, cable, or switch. The worst thing that may happen in the case of a switch failure is that half of the hosts will be temporarily -unreachable until the other switch expires its tables. +unreachable until the other switch expires its tables. Example 2: Using multiple ethernet cards connected to a switch to configure - NIC failover (switch is not required to support trunking). + NIC failover (switch is not required to support trunking). +----------+ +----------+ @@ -947,6 +922,41 @@ just ignore all the warnings it emits. +8021q VLAN support +================== + +It is possible to configure VLAN devices over a bond interface using the 8021q +driver. However, only packets coming from the 8021q driver and passing through +bonding will be tagged by default. Self generated packets, like bonding's +learning packets or ARP packets generated by either ALB mode or the ARP +monitor mechanism, are tagged internally by bonding itself. As a result, +bonding has to "learn" what VLAN IDs are configured on top of it, and it uses +those IDs to tag self generated packets. + +For simplicity reasons, and to support the use of adapters that can do VLAN +hardware acceleration offloding, the bonding interface declares itself as +fully hardware offloaing capable, it gets the add_vid/kill_vid notifications +to gather the necessary information, and it propagates those actions to the +slaves. +In case of mixed adapter types, hardware accelerated tagged packets that should +go through an adapter that is not offloading capable are "un-accelerated" by the +bonding driver so the VLAN tag sits in the regular location. + +VLAN interfaces *must* be added on top of a bonding interface only after +enslaving at least one slave. This is because until the first slave is added the +bonding interface has a HW address of 00:00:00:00:00:00, which will be copied by +the VLAN interface when it is created. + +Notice that a problem would occur if all slaves are released from a bond that +still has VLAN interfaces on top of it. When later coming to add new slaves, the +bonding interface would get a HW address from the first slave, which might not +match that of the VLAN interfaces. It is recommended that either all VLANs are +removed and then re-added, or to manually set the bonding interface's HW +address so it matches the VLAN's. (Note: changing a VLAN interface's HW address +would set the underlying device -- i.e. the bonding interface -- to promiscouos +mode, which might not be what you want). + + Limitations =========== The main limitations are : @@ -957,7 +967,7 @@ servers, but may be useful when the front switches send multicast information on their links (e.g. VRRP), or even health-check the servers. Use the arp_interval/arp_ip_target parameters to count incoming/outgoing - frames. + frames. diff -urN linux-2.4.25/Documentation/networking/ifenslave.c linux-2.4.26/Documentation/networking/ifenslave.c --- linux-2.4.25/Documentation/networking/ifenslave.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/Documentation/networking/ifenslave.c 2004-04-14 06:05:25.000000000 -0700 @@ -4,8 +4,6 @@ * This program controls the Linux implementation of running multiple * network interfaces in parallel. * - * Usage: ifenslave [-v] master-interface < slave-interface [metric ] > ... - * * Author: Donald Becker * Copyright 1994-1996 Donald Becker * @@ -90,24 +88,30 @@ * - For opt_c: slave should not be set to the master's setting * while it is running. It was already set during enslave. To * simplify things, it is now handeled separately. + * + * - 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * set version to 1.1.0 */ -#define APP_VERSION "1.0.12" -#define APP_RELDATE "June 30, 2003" +#define APP_VERSION "1.1.0" +#define APP_RELDATE "December 1, 2003" #define APP_NAME "ifenslave" static char *version = -APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ") " "\nDonald Becker (becker@cesdis.gsfc.nasa.gov).\n" -"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" -"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n"; +APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n" +"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n" +"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n" +"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n" +" (ctindel at ieee dot org).\n"; static const char *usage_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n"; +"Usage: ifenslave [-f] [...]\n" +" ifenslave -d [...]\n" +" ifenslave -c \n" +" ifenslave --help\n"; -static const char *howto_msg = -"Usage: ifenslave [-adfrvVh] < [metric ] > ...\n" -" ifenslave -c master-interface slave-if\n" +static const char *help_msg = "\n" " To create a bond device, simply follow these three steps :\n" " - ensure that the required drivers are properly loaded :\n" @@ -115,18 +119,32 @@ " - assign an IP address to the bond device :\n" " # ifconfig bond0 netmask broadcast \n" " - attach all the interfaces you need to the bond device :\n" -" # ifenslave bond0 eth0 eth1 eth2\n" +" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n" " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" " interfaces attached AFTER this assignment will get the same MAC addr.\n" -"\n" -" To detach a dead interface without setting the bond device down :\n" -" # ifenslave -d bond0 eth1\n" +" (except for ALB/TLB modes)\n" "\n" " To set the bond device down and automatically release all the slaves :\n" " # ifconfig bond0 down\n" "\n" +" To detach a dead interface without setting the bond device down :\n" +" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n" +"\n" " To change active slave :\n" -" # ifenslave -c bond0 eth0\n" +" # ifenslave {-c|--change-active} bond0 eth0\n" +"\n" +" To show master interface info\n" +" # ifenslave bond0\n" +"\n" +" To show all interfaces info\n" +" # ifenslave {-a|--all-interfaces}\n" +"\n" +" To be more verbose\n" +" # ifenslave {-v|--verbose} ...\n" +"\n" +" # ifenslave {-u|--usage} Show usage\n" +" # ifenslave {-V|--version} Show version\n" +" # ifenslave {-h|--help} This message\n" "\n"; #include @@ -153,476 +171,332 @@ #include struct option longopts[] = { - /* { name has_arg *flag val } */ - {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ - {"force", 0, 0, 'f'}, /* Force the operation. */ - {"help", 0, 0, '?'}, /* Give help */ - {"howto", 0, 0, 'h'}, /* Give some more help */ - {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */ - {"verbose", 0, 0, 'v'}, /* Report each action taken. */ - {"version", 0, 0, 'V'}, /* Emit version information. */ - {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ - {"change-active", 0, 0, 'c'}, /* Change the active slave. */ - { 0, 0, 0, 0 } + /* { name has_arg *flag val } */ + {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */ + {"change-active", 0, 0, 'c'}, /* Change the active slave. */ + {"detach", 0, 0, 'd'}, /* Detach a slave interface. */ + {"force", 0, 0, 'f'}, /* Force the operation. */ + {"help", 0, 0, 'h'}, /* Give help */ + {"usage", 0, 0, 'u'}, /* Give usage */ + {"verbose", 0, 0, 'v'}, /* Report each action taken. */ + {"version", 0, 0, 'V'}, /* Emit version information. */ + { 0, 0, 0, 0} }; /* Command-line flags. */ unsigned int -opt_a = 0, /* Show-all-interfaces flag. */ -opt_f = 0, /* Force the operation. */ -opt_r = 0, /* Set up a Rx-only slave. */ -opt_d = 0, /* detach a slave interface. */ -opt_c = 0, /* change-active-slave flag. */ -verbose = 0, /* Verbose flag. */ -opt_version = 0, -opt_howto = 0; -int skfd = -1; /* AF_INET socket for ioctl() calls. */ +opt_a = 0, /* Show-all-interfaces flag. */ +opt_c = 0, /* Change-active-slave flag. */ +opt_d = 0, /* Detach a slave interface. */ +opt_f = 0, /* Force the operation. */ +opt_h = 0, /* Help */ +opt_u = 0, /* Usage */ +opt_v = 0, /* Verbose flag. */ +opt_V = 0; /* Version */ + +int skfd = -1; /* AF_INET socket for ioctl() calls.*/ +int abi_ver = 0; /* userland - kernel ABI version */ +int hwaddr_set = 0; /* Master's hwaddr is set */ +int saved_errno; + +struct ifreq master_mtu, master_flags, master_hwaddr; +struct ifreq slave_mtu, slave_flags, slave_hwaddr; + +struct dev_ifr { + struct ifreq *req_ifr; + char *req_name; + int req_type; +}; + +struct dev_ifr master_ifra[] = { + {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; + +struct dev_ifr slave_ifra[] = { + {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU}, + {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS}, + {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR}, + {NULL, "", 0} +}; static void if_print(char *ifname); -static int get_abi_ver(char *master_ifname); +static int get_drv_info(char *master_ifname); +static int get_if_settings(char *ifname, struct dev_ifr ifra[]); +static int get_slave_flags(char *slave_ifname); +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr); +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr); +static int set_slave_mtu(char *slave_ifname, int mtu); +static int set_if_flags(char *ifname, short flags); +static int set_if_up(char *ifname, short flags); +static int set_if_down(char *ifname, short flags); +static int clear_if_addr(char *ifname); +static int set_if_addr(char *master_ifname, char *slave_ifname); +static int change_active(char *master_ifname, char *slave_ifname); +static int enslave(char *master_ifname, char *slave_ifname); +static int release(char *master_ifname, char *slave_ifname); +#define v_print(fmt, args...) \ + if (opt_v) \ + fprintf(stderr, fmt, ## args ) -int -main(int argc, char **argv) +int main(int argc, char *argv[]) { - struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr; - struct ifreq if_netmask, if_brdaddr, if_flags; - int rv, goterr = 0; - int c, errflag = 0; - sa_family_t master_family; char **spp, *master_ifname, *slave_ifname; - int hwaddr_notset; - int abi_ver = 0; + int c, i, rv; + int res = 0; + int exclusive = 0; - while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF) + while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) { switch (c) { - case 'a': opt_a++; break; - case 'f': opt_f++; break; - case 'r': opt_r++; break; - case 'd': opt_d++; break; - case 'c': opt_c++; break; - case 'v': verbose++; break; - case 'V': opt_version++; break; - case 'h': opt_howto++; break; - case '?': errflag++; - } + case 'a': opt_a++; exclusive++; break; + case 'c': opt_c++; exclusive++; break; + case 'd': opt_d++; exclusive++; break; + case 'f': opt_f++; exclusive++; break; + case 'h': opt_h++; exclusive++; break; + case 'u': opt_u++; exclusive++; break; + case 'v': opt_v++; break; + case 'V': opt_V++; exclusive++; break; - /* option check */ - if (opt_c) - if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version || - opt_howto || errflag ) { + case '?': fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } + } - if (errflag) { + /* options check */ + if (exclusive > 1) { fprintf(stderr, usage_msg); - return 2; + res = 2; + goto out; } - if (opt_howto) { - fprintf(stderr, howto_msg); - return 0; + if (opt_v || opt_V) { + printf(version); + if (opt_V) { + res = 0; + goto out; + } } - if (verbose || opt_version) { - printf(version); - if (opt_version) - exit(0); + if (opt_u) { + printf(usage_msg); + res = 0; + goto out; } - /* Open a basic socket. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { - perror("socket"); - exit(-1); + if (opt_h) { + printf(usage_msg); + printf(help_msg); + res = 0; + goto out; } - if (verbose) - fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n", - argc, optind, argv[optind]); + /* Open a basic socket */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + res = 1; + goto out; + } - /* No remaining args means show all interfaces. */ - if (optind == argc) { - if_print((char *)NULL); - (void) close(skfd); - exit(0); + if (opt_a) { + if (optind == argc) { + /* No remaining args */ + /* show all interfaces */ + if_print((char *)NULL); + goto out; + } else { + /* Just show usage */ + fprintf(stderr, usage_msg); + res = 2; + goto out; + } } - /* Copy the interface name. */ + /* Copy the interface name */ spp = argv + optind; master_ifname = *spp++; - slave_ifname = *spp++; - /* Check command line. */ - if (opt_c) { - char **tempp = spp; - if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) { - fprintf(stderr, usage_msg); - (void) close(skfd); - return 2; - } + if (master_ifname == NULL) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* A single args means show the configuration for this interface. */ - if (slave_ifname == NULL) { - if_print(master_ifname); - (void) close(skfd); - exit(0); + /* exchange abi version with bonding module */ + res = get_drv_info(master_ifname); + if (res) { + fprintf(stderr, + "Master '%s': Error: handshake with driver failed. " + "Aborting\n", + master_ifname); + goto out; } - /* exchange abi version with bonding driver */ - abi_ver = get_abi_ver(master_ifname); - if (abi_ver < 0) { - (void) close(skfd); - exit(1); - } - - /* Get the vitals from the master interface. */ - { - struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr, - &if_brdaddr, &if_netmask, &if_flags, - &if_hwaddr }; - const char *req_name[7] = { - "IP address", "MTU", "destination address", - "broadcast address", "netmask", "status flags", - "hardware address" }; - const int ioctl_req_type[7] = { - SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR, - SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS, - SIOCGIFHWADDR }; - int i; - - for (i = 0; i < 7; i++) { - strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ); - if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) { - fprintf(stderr, - "Something broke getting the master's %s: %s.\n", - req_name[i], strerror(errno)); - } - } - - /* check if master is up; if not then fail any operation */ - if (!(if_flags.ifr_flags & IFF_UP)) { - fprintf(stderr, "Illegal operation; the specified master interface '%s' is not up.\n", master_ifname); - (void) close(skfd); - exit (1); - } + slave_ifname = *spp++; - hwaddr_notset = 1; /* assume master's address not set yet */ - for (i = 0; hwaddr_notset && (i < 6); i++) { - hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0; + if (slave_ifname == NULL) { + if (opt_d || opt_c) { + fprintf(stderr, usage_msg); + res = 2; + goto out; } - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) { - fprintf(stderr, "The specified master interface '%s' is not" - " ethernet-like.\n This program is designed to work" - " with ethernet-like network interfaces.\n" - " Use the '-f' option to force the operation.\n", - master_ifname); - (void) close(skfd); - exit (1); - } - master_family = if_hwaddr.ifr_hwaddr.sa_family; - if (verbose) { - unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data; - printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* A single arg means show the + * configuration for this interface + */ + if_print(master_ifname); + goto out; } + res = get_if_settings(master_ifname, master_ifra); + if (res) { + /* Probably a good reason not to go on */ + fprintf(stderr, + "Master '%s': Error: get settings failed: %s. " + "Aborting\n", + master_ifname, strerror(res)); + goto out; + } - /* do this when enslaving interfaces */ - do { - if (opt_d) { /* detach a slave interface from the master */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) && - (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n", - slave_ifname, master_ifname, strerror(errno)); - } - else if (abi_ver < 1) { - /* The driver is using an old ABI, so we'll set the interface - * down to avoid any conflicts due to same IP/MAC - */ - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - } - else { - ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING); - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - } - } else if (opt_c) { /* change primary slave */ - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && - (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); - } - } else { /* attach a slave interface to the master */ - - strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname, - strerror(saved_errno)); - (void) close(skfd); - return 1; - } - - if ((ifr2.ifr_flags & IFF_SLAVE) && !opt_r) { - fprintf(stderr, "%s is already a slave\n", slave_ifname); - (void) close(skfd); - return 1; - } - - /* if hwaddr_notset, assign the slave hw address to the master */ - if (hwaddr_notset) { - /* assign the slave hw address to the - * master since it currently does not - * have one; otherwise, slaves may - * have different hw addresses in - * active-backup mode as seen when enslaving - * using "ifenslave bond0 eth0 eth1" because - * hwaddr_notset is set outside this loop. - * TODO: put this and the "else" portion in - * a function. - */ - /* get the slaves MAC address */ - strncpy(if_hwaddr.ifr_name, slave_ifname, - IFNAMSIZ); - rv = ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr); - if (-1 == rv) { - fprintf(stderr, "Could not get MAC " - "address of %s: %s\n", - slave_ifname, - strerror(errno)); - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - goterr = 1; - } - - if (!goterr) { - if (abi_ver < 1) { - /* In ABI versions older than 1, the - * master's set_mac routine couldn't - * work if it was up, because it - * used the default ethernet set_mac - * function. - */ - /* bring master down */ - if_flags.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - goterr = 1; - fprintf(stderr, - "Shutting down " - "interface %s failed: " - "%s\n", - master_ifname, - strerror(errno)); - } - } - - strncpy(if_hwaddr.ifr_name, - master_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, - &if_hwaddr) < 0) { - fprintf(stderr, - "Could not set MAC " - "address of %s: %s\n", - master_ifname, - strerror(errno)); - goterr=1; - } else { - hwaddr_notset = 0; - } - - if (abi_ver < 1) { - /* bring master back up */ - if_flags.ifr_flags |= IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, - &if_flags) < 0) { - fprintf(stderr, - "Bringing up interface " - "%s failed: %s\n", - master_ifname, - strerror(errno)); - } - } - } - } else if (abi_ver < 1) { /* if (hwaddr_notset) */ - - /* The driver is using an old ABI, so we'll set the interface - * down and assign the master's hwaddr to it - */ - if (ifr2.ifr_flags & IFF_UP) { - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } - } - - strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { - int saved_errno = errno; - fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, - strerror(saved_errno)); - if (saved_errno == EBUSY) - fprintf(stderr, " The slave device %s is busy: it must be" - " idle before running this command.\n", slave_ifname); - else if (saved_errno == EOPNOTSUPP) - fprintf(stderr, " The slave device you specified does not support" - " setting the MAC address.\n Your kernel likely does not" - " support slave devices.\n"); - else if (saved_errno == EINVAL) - fprintf(stderr, " The slave device's address type does not match" - " the master's address type.\n"); - } else { - if (verbose) { - unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; - printf("Slave's (%s) hardware address set to " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, - hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } - } - } + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master_flags.ifr_flags & IFF_MASTER)) { + fprintf(stderr, + "Illegal operation; the specified interface '%s' " + "is not a master. Aborting\n", + master_ifname); + res = 1; + goto out; + } - if (*spp && !strcmp(*spp, "metric")) { - if (*++spp == NULL) { - fprintf(stderr, usage_msg); - (void) close(skfd); - exit(2); - } - if_metric.ifr_metric = atoi(*spp); - strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); - if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { - fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, - strerror(errno)); - goterr = 1; - } - spp++; - } + /* check if master is up; if not then fail any operation */ + if (!(master_flags.ifr_flags & IFF_UP)) { + fprintf(stderr, + "Illegal operation; the specified master interface " + "'%s' is not up.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave's address: %s.\n", - strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; - printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + /* Only for enslaving */ + if (!opt_c && !opt_d) { + sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family; + unsigned char *hwaddr = + (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data; - if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { - fprintf(stderr, "Something broke setting the slave MTU: %s.\n", - strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); - } + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master_family != 1 && !opt_f) { + fprintf(stderr, + "Illegal operation: The specified master " + "interface '%s' is not ethernet-like.\n " + "This program is designed to work with " + "ethernet-like network interfaces.\n " + "Use the '-f' option to force the " + "operation.\n", + master_ifname); + res = 1; + goto out; + } - if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { - fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; - printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } + /* Check master's hw addr */ + for (i = 0; i < 6; i++) { + if (hwaddr[i] != 0) { + hwaddr_set = 1; + break; } + } - if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) broadcast address: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; - printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - } - } + if (hwaddr_set) { + v_print("current hardware address of master '%s' " + "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "type %d\n", + master_ifname, + hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], + hwaddr[4], hwaddr[5], + master_family); + } + } - if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) netmask: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) { - unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; - printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", - slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + /* Accepts only one slave */ + if (opt_c) { + /* change active slave */ + res = get_slave_flags(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: get flags failed. " + "Aborting\n", + slave_ifname); + goto out; + } + res = change_active(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Change active failed\n", + master_ifname, slave_ifname); + } + } else { + /* Accept multiple slaves */ + do { + if (opt_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get flags " + "failed. Skipping\n", + slave_ifname); + res = rv; + continue; } - } - - if (abi_ver < 1) { - - /* The driver is using an old ABI, so we'll set the interface - * up before enslaving it - */ - ifr2.ifr_flags |= IFF_UP; - if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 - || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 - || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - fprintf(stderr, - "Something broke setting the slave (%s) flags: %s.\n", - slave_ifname, strerror(errno)); - } else { - if (verbose) - printf("Set the slave's (%s) flags %4.4x.\n", - slave_ifname, if_flags.ifr_flags); + rv = release(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Release failed\n", + master_ifname, slave_ifname); + res = rv; } } else { - /* the bonding module takes care of setting the slave's mac address - * and opening its interface - */ - if (ifr2.ifr_flags & IFF_UP) { /* the interface will need to be down */ - ifr2.ifr_flags &= ~IFF_UP; - if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { - int saved_errno = errno; - fprintf(stderr, "Shutting down interface %s failed: %s\n", - slave_ifname, strerror(saved_errno)); - } + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, slave_ifra); + if (rv) { + /* Can't work with this slave. */ + /* remember the error and skip it*/ + fprintf(stderr, + "Slave '%s': Error: get " + "settings failed: %s. " + "Skipping\n", + slave_ifname, strerror(rv)); + res = rv; + continue; } - } - - /* Do the real thing */ - if (!opt_r) { - strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); - strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); - if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && - (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { - fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + rv = enslave(master_ifname, slave_ifname); + if (rv) { + fprintf(stderr, + "Master '%s', Slave '%s': Error: " + "Enslave failed\n", + master_ifname, slave_ifname); + res = rv; } } - } - } while ( (slave_ifname = *spp++) != NULL); + } while ((slave_ifname = *spp++) != NULL); + } - /* Close the socket. */ - (void) close(skfd); +out: + if (skfd >= 0) { + close(skfd); + } - return(goterr); + return res; } static short mif_flags; @@ -631,35 +505,34 @@ static int if_getconfig(char *ifname) { struct ifreq ifr; - int metric, mtu; /* Parameters of the master interface. */ + int metric, mtu; /* Parameters of the master interface. */ struct sockaddr dstaddr, broadaddr, netmask; + unsigned char *hwaddr; strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) return -1; mif_flags = ifr.ifr_flags; printf("The result of SIOCGIFFLAGS on %s is %x.\n", - ifname, ifr.ifr_flags); + ifname, ifr.ifr_flags); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) return -1; printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", - ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], - ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) return -1; - { - /* Gotta convert from 'char' to unsigned for printf(). */ - unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; - printf("The result of SIOCGIFHWADDR is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); - } + /* Gotta convert from 'char' to unsigned for printf(). */ + hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); strcpy(ifr.ifr_name, ifname); if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { @@ -691,7 +564,7 @@ } else netmask = ifr.ifr_netmask; - return(0); + return 0; } static void if_print(char *ifname) @@ -705,15 +578,16 @@ ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + perror("SIOCGIFCONF failed"); return; } ifr = ifc.ifc_req; for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if (if_getconfig(ifr->ifr_name) < 0) { - fprintf(stderr, "%s: unknown interface.\n", - ifr->ifr_name); + fprintf(stderr, + "%s: unknown interface.\n", + ifr->ifr_name); continue; } @@ -721,16 +595,18 @@ /*ife_print(&ife);*/ } } else { - if (if_getconfig(ifname) < 0) - fprintf(stderr, "%s: unknown interface.\n", ifname); + if (if_getconfig(ifname) < 0) { + fprintf(stderr, + "%s: unknown interface.\n", ifname); + } } } -static int get_abi_ver(char *master_ifname) +static int get_drv_info(char *master_ifname) { struct ifreq ifr; struct ethtool_drvinfo info; - int abi_ver = 0; + char *endptr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); @@ -739,24 +615,487 @@ info.cmd = ETHTOOL_GDRVINFO; strncpy(info.driver, "ifenslave", 32); snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (ioctl(skfd, SIOCETHTOOL, &ifr) >= 0) { - char *endptr; - abi_ver = strtoul(info.fw_version, &endptr, 0); - if (*endptr) { - fprintf(stderr, "Error: got invalid string as an ABI " - "version from the bonding module\n"); - return -1; + if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) { + if (errno == EOPNOTSUPP) { + goto out; } + + saved_errno = errno; + v_print("Master '%s': Error: get bonding info failed %s\n", + master_ifname, strerror(saved_errno)); + return 1; } - if (verbose) { - printf("ABI ver is %d\n", abi_ver); + abi_ver = strtoul(info.fw_version, &endptr, 0); + if (*endptr) { + v_print("Master '%s': Error: got invalid string as an ABI " + "version from the bonding module\n", + master_ifname); + return 1; } - return abi_ver; + +out: + v_print("ABI ver is %d\n", abi_ver); + + return 0; } +static int change_active(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: " + "%s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + return res; +} + +static int enslave(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (slave_flags.ifr_flags & IFF_SLAVE) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is already a slave\n", + slave_ifname); + return 1; + } + + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface down failed\n", + slave_ifname); + return res; + } + + if (abi_ver < 2) { + /* Older bonding versions would panic if the slave has no IP + * address, so get the IP setting from the master. + */ + res = set_if_addr(master_ifname, slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set address failed\n", + slave_ifname); + return res; + } + } else { + res = clear_if_addr(slave_ifname); + if (res) { + fprintf(stderr, + "Slave '%s': Error: clear address failed\n", + slave_ifname); + return res; + } + } + + if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) { + res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set MTU failed\n", + slave_ifname); + return res; + } + } + + if (hwaddr_set) { + /* Master already has an hwaddr + * so set it's hwaddr to the slave + */ + if (abi_ver < 1) { + /* The driver is using an old ABI, so + * the application sets the slave's + * hwaddr + */ + res = set_slave_hwaddr(slave_ifname, + &(master_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Slave '%s': Error: set hw address " + "failed\n", + slave_ifname); + goto undo_mtu; + } + + /* For old ABI the application needs to bring the + * slave back up + */ + res = set_if_up(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + goto undo_slave_mac; + } + } + /* The driver is using a new ABI, + * so the driver takes care of setting + * the slave's hwaddr and bringing + * it up again + */ + } else { + /* No hwaddr for master yet, so + * set the slave's hwaddr to it + */ + if (abi_ver < 1) { + /* For old ABI, the master needs to be + * down before setting it's hwaddr + */ + res = set_if_down(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "down failed\n", + master_ifname); + goto undo_mtu; + } + } + + res = set_master_hwaddr(master_ifname, + &(slave_hwaddr.ifr_hwaddr)); + if (res) { + fprintf(stderr, + "Master '%s': Error: set hw address " + "failed\n", + master_ifname); + goto undo_mtu; + } + + if (abi_ver < 1) { + /* For old ABI, bring the master + * back up + */ + res = set_if_up(master_ifname, master_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Master '%s': Error: bring interface " + "up failed\n", + master_ifname); + goto undo_master_mac; + } + } + + hwaddr_set = 1; + } + + /* Do the real thing */ + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n", + master_ifname, strerror(saved_errno)); + res = 1; + } + + if (res) { + goto undo_master_mac; + } + + return 0; + +/* rollback (best effort) */ +undo_master_mac: + set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr)); + hwaddr_set = 0; + goto undo_mtu; +undo_slave_mac: + set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr)); +undo_mtu: + set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu); + return res; +} + +static int release(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res = 0; + + if (!(slave_flags.ifr_flags & IFF_SLAVE)) { + fprintf(stderr, + "Illegal operation: The specified slave interface " + "'%s' is not a slave\n", + slave_ifname); + return 1; + } + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ); + if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) && + (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n", + master_ifname, strerror(saved_errno)); + return 1; + } else if (abi_ver < 1) { + /* The driver is using an old ABI, so we'll set the interface + * down to avoid any conflicts due to same MAC/IP + */ + res = set_if_down(slave_ifname, slave_flags.ifr_flags); + if (res) { + fprintf(stderr, + "Slave '%s': Error: bring interface " + "down failed\n", + slave_ifname); + } + } + + /* set to default mtu */ + set_slave_mtu(slave_ifname, 1500); + + return res; +} + +static int get_if_settings(char *ifname, struct dev_ifr ifra[]) +{ + int i; + int res = 0; + + for (i = 0; ifra[i].req_ifr; i++) { + strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: %s failed: %s\n", + ifname, ifra[i].req_name, + strerror(saved_errno)); + + return saved_errno; + } + } + + return 0; +} + +static int get_slave_flags(char *slave_ifname) +{ + int res = 0; + + strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave %s: flags %04X.\n", + slave_ifname, slave_flags.ifr_flags); + } + + return res; +} + +static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n", + master_ifname, strerror(saved_errno)); + return res; + } else { + v_print("Master '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + master_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr) +{ + unsigned char *addr = (unsigned char *)hwaddr->sa_data; + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr)); + res = ioctl(skfd, SIOCSIFHWADDR, &ifr); + if (res < 0) { + saved_errno = errno; + + v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n", + slave_ifname, strerror(saved_errno)); + + if (saved_errno == EBUSY) { + v_print(" The device is busy: it must be idle " + "before running this command.\n"); + } else if (saved_errno == EOPNOTSUPP) { + v_print(" The device does not support setting " + "the MAC address.\n" + " Your kernel likely does not support slave " + "devices.\n"); + } else if (saved_errno == EINVAL) { + v_print(" The device's address type does not match " + "the master's address type.\n"); + } + return res; + } else { + v_print("Slave '%s': hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + slave_ifname, addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + } + + return res; +} + +static int set_slave_mtu(char *slave_ifname, int mtu) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_mtu = mtu; + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFMTU, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n", + slave_ifname, strerror(saved_errno)); + } else { + v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu); + } + + return res; +} + +static int set_if_flags(char *ifname, short flags) +{ + struct ifreq ifr; + int res = 0; + + ifr.ifr_flags = flags; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + res = ioctl(skfd, SIOCSIFFLAGS, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': flags set to %04X.\n", ifname, flags); + } + + return res; +} + +static int set_if_up(char *ifname, short flags) +{ + return set_if_flags(ifname, flags | IFF_UP); +} + +static int set_if_down(char *ifname, short flags) +{ + return set_if_flags(ifname, flags & ~IFF_UP); +} + +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; + int res = 0; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + + res = ioctl(skfd, SIOCSIFADDR, &ifr); + if (res < 0) { + saved_errno = errno; + v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n", + ifname, strerror(saved_errno)); + } else { + v_print("Interface '%s': address cleared\n", ifname); + } + + return res; +} + +static int set_if_addr(char *master_ifname, char *slave_ifname) +{ + struct ifreq ifr; + int res; + unsigned char *ipaddr; + int i; + struct { + char *req_name; + char *desc; + int g_ioctl; + int s_ioctl; + } ifra[] = { + {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR}, + {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR}, + {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR}, + {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK}, + {NULL, NULL, 0, 0}, + }; + + for (i = 0; ifra[i].req_name; i++) { + strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].g_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCG%s failed: %s\n", + master_ifname, ifra[i].req_name, + strerror(saved_errno)); + + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ); + res = ioctl(skfd, ifra[i].s_ioctl, &ifr); + if (res < 0) { + int saved_errno = errno; + + v_print("Interface '%s': Error: SIOCS%s failed: %s\n", + slave_ifname, ifra[i].req_name, + strerror(saved_errno)); + + return res; + } + + ipaddr = ifr.ifr_addr.sa_data; + v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n", + slave_ifname, ifra[i].desc, + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + + return 0; +} /* * Local variables: @@ -768,3 +1107,4 @@ * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" * End: */ + diff -urN linux-2.4.25/Documentation/networking/ip-sysctl.txt linux-2.4.26/Documentation/networking/ip-sysctl.txt --- linux-2.4.25/Documentation/networking/ip-sysctl.txt 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.26/Documentation/networking/ip-sysctl.txt 2004-04-14 06:05:25.000000000 -0700 @@ -481,6 +481,55 @@ conf/{all,interface}/arp_filter is set to TRUE, it will be disabled otherwise +arp_announce - INTEGER + Define different restriction levels for announcing the local + source IP address from IP packets in ARP requests sent on + interface: + 0 - (default) Use any local address, configured on any interface + 1 - Try to avoid local addresses that are not in the target's + subnet for this interface. This mode is useful when target + hosts reachable via this interface require the source IP + address in ARP requests to be part of their logical network + configured on the receiving interface. When we generate the + request we will check all our subnets that include the + target IP and will preserve the source address if it is from + such subnet. If there is no such subnet we select source + address according to the rules for level 2. + 2 - Always use the best local address for this target. + In this mode we ignore the source address in the IP packet + and try to select local address that we prefer for talks with + the target host. Such local address is selected by looking + for primary IP addresses on all our subnets on the outgoing + interface that include the target IP address. If no suitable + local address is found we select the first local address + we have on the outgoing interface or on all other interfaces, + with the hope we will receive reply for our request and + even sometimes no matter the source IP address we announce. + + The max value from conf/{all,interface}/arp_announce is used. + + Increasing the restriction level gives more chance for + receiving answer from the resolved target while decreasing + the level announces more valid sender's information. + +arp_ignore - INTEGER + Define different modes for sending replies in response to + received ARP requests that resolve local target IP addresses: + 0 - (default): reply for any local target IP address, configured + on any interface + 1 - reply only if the target IP address is local address + configured on the incoming interface + 2 - reply only if the target IP address is local address + configured on the incoming interface and both with the + sender's IP address are part from same subnet on this interface + 3 - do not reply for local addresses configured with scope host, + only resolutions for global and link addresses are replied + 4-7 - reserved + 8 - do not reply for all local addresses + + The max value from conf/{all,interface}/arp_ignore is used + when ARP request is received on the {interface} + tag - INTEGER Allows you to write a number, which can be used as required. Default value is 0. diff -urN linux-2.4.25/Documentation/networking/packet_mmap.txt linux-2.4.26/Documentation/networking/packet_mmap.txt --- linux-2.4.25/Documentation/networking/packet_mmap.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/Documentation/networking/packet_mmap.txt 2004-04-14 06:05:25.000000000 -0700 @@ -0,0 +1,412 @@ + +DaveM: + +If you agree with it I will send two small patches to modify +kernel's configure help. + + Ulisses + +-------------------------------------------------------------------------------- ++ ABSTRACT +-------------------------------------------------------------------------------- + +This file documents the CONFIG_PACKET_MMAP option available with the PACKET +socket interface on 2.4 and 2.6 kernels. This type of sockets is used for +capture network traffic with utilities like tcpdump or any other that uses +the libpcap library. + +You can find the latest version of this document at + + http://pusa.uv.es/~ulisses/packet_mmap/ + +Please send me your comments to + + Ulisses Alonso Camaró + +------------------------------------------------------------------------------- ++ Why use PACKET_MMAP +-------------------------------------------------------------------------------- + +In Linux 2.4/2.6 if PACKET_MMAP is not enabled, the capture process is very +inefficient. It uses very limited buffers and requires one system call +to capture each packet, it requires two if you want to get packet's +timestamp (like libpcap always does). + +In the other hand PACKET_MMAP is very efficient. PACKET_MMAP provides a size +configurable circular buffer mapped in user space. This way reading packets just +needs to wait for them, most of the time there is no need to issue a single +system call. By using a shared buffer between the kernel and the user +also has the benefit of minimizing packet copies. + +It's fine to use PACKET_MMAP to improve the performance of the capture process, +but it isn't everything. At least, if you are capturing at high speeds (this +is relative to the cpu speed), you should check if the device driver of your +network interface card supports some sort of interrupt load mitigation or +(even better) if it supports NAPI, also make sure it is enabled. + +-------------------------------------------------------------------------------- ++ How to use CONFIG_PACKET_MMAP +-------------------------------------------------------------------------------- + +From the user standpoint, you should use the higher level libpcap library, wich +is a de facto standard, portable across nearly all operating systems +including Win32. + +Said that, at time of this writing, official libpcap 0.8.1 is out and doesn't include +support for PACKET_MMAP, and also probably the libpcap included in your distribution. + +I'm aware of two implementations of PACKET_MMAP in libpcap: + + http://pusa.uv.es/~ulisses/packet_mmap/ (by Simon Patarin, based on libpcap 0.6.2) + http://public.lanl.gov/cpw/ (by Phil Wood, based on lastest libpcap) + +The rest of this document is intended for people who want to understand +the low level details or want to improve libpcap by including PACKET_MMAP +support. + +-------------------------------------------------------------------------------- ++ How to use CONFIG_PACKET_MMAP directly +-------------------------------------------------------------------------------- + +From the system calls stand point, the use of PACKET_MMAP involves +the following process: + + +[setup] socket() -------> creation of the capture socket + setsockopt() ---> allocation of the circular buffer (ring) + mmap() ---------> maping of the allocated buffer to the + user process + +[capture] poll() ---------> to wait for incoming packets + +[shutdown] close() --------> destruction of the capture socket and + deallocation of all associated + resources. + + +socket creation and destruction is straight forward, and is done +the same way with or without PACKET_MMAP: + +int fd; + +fd= socket(PF_PACKET, mode, htons(ETH_P_ALL)) + +where mode is SOCK_RAW for the raw interface were link level +information can be captured or SOCK_DGRAM for the cooked +interface where link level information capture is not +supported and a link level pseudo-header is provided +by the kernel. + +The destruction of the socket and all associated resources +is done by a simple call to close(fd). + +Next I will describe PACKET_MMAP settings and it's constraints, +also the maping of the circular buffer in the user process and +the use of this buffer. + +-------------------------------------------------------------------------------- ++ PACKET_MMAP settings +-------------------------------------------------------------------------------- + + +To setup PACKET_MMAP from user level code is done with a call like + + setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req)) + +The most significant argument in the previous call is the req parameter, +this parameter must to have the following structure: + + struct tpacket_req + { + unsigned int tp_block_size; /* Minimal size of contiguous block */ + unsigned int tp_block_nr; /* Number of blocks */ + unsigned int tp_frame_size; /* Size of frame */ + unsigned int tp_frame_nr; /* Total number of frames */ + }; + +This structure is defined in /usr/include/linux/if_packet.h and establishes a +circular buffer (ring) of unswappable memory mapped in the capture process. +Being mapped in the capture process allows reading the captured frames and +related meta-information like timestamps without requiring a system call. + +Captured frames are grouped in blocks. Each block is a physically contiguous +region of memory and holds tp_block_size/tp_frame_size frames. The total number +of blocks is tp_block_nr. Note that tp_frame_nr is a redundant parameter because + + frames_per_block = tp_block_size/tp_frame_size + +indeed, packet_set_ring checks that the following condition is true + + frames_per_block * tp_block_nr == tp_frame_nr + + +Lets see an example, with the following values: + + tp_block_size= 4096 + tp_frame_size= 2048 + tp_block_nr = 4 + tp_frame_nr = 8 + +we will get the following buffer structure: + + block #1 block #2 ++---------+---------+ +---------+---------+ +| frame 1 | frame 2 | | frame 3 | frame 4 | ++---------+---------+ +---------+---------+ + + block #3 block #4 ++---------+---------+ +---------+---------+ +| frame 5 | frame 6 | | frame 7 | frame 8 | ++---------+---------+ +---------+---------+ + +A frame can be of any size with the only condition it can fit in a block. A block +can only hold an integer number of frames, or in other words, a frame cannot +be spawn accross two blocks so there are some datails you have to take into +account when choosing the frame_size. See "Maping and use of the circular +buffer (ring)". + + +-------------------------------------------------------------------------------- ++ PACKET_MMAP setting constraints +-------------------------------------------------------------------------------- + +In kernel versions prior to 2.4.26 (for the 2.4 branch) and 2.6.5 (2.6 branch), +the PACKET_MMAP buffer could hold only 32768 frames in a 32 bit architecture or +16384 in a 64 bit architecture. For information on these kernel versions +see http://pusa.uv.es/~ulisses/packet_mmap/packet_mmap.pre-2.4.26_2.6.5.txt + + Block size limit +------------------ + +As stated earlier, each block is a contiguous physical region of memory. These +memory regions are allocated with calls to the __get_free_pages() function. As +the name indicates, this function allocates pages of memory, and the second +argument is "order" or a power of two number of pages, that is +(for PAGE_SIZE == 4096) order=0 ==> 4096 bytes, order=1 ==> 8192 bytes, +order=2 ==> 16384 bytes, etc. The maximum size of a +region allocated by __get_free_pages is determined by the MAX_ORDER macro. More +precisely the limit can be calculated as: + + PAGE_SIZE << MAX_ORDER + + In a i386 architecture PAGE_SIZE is 4096 bytes + In a 2.4/i386 kernel MAX_ORDER is 10 + In a 2.6/i386 kernel MAX_ORDER is 11 + +So get_free_pages can allocate as much as 4MB or 8MB in a 2.4/2.6 kernel +respectively, with an i386 architecture. + +User space programs can include /usr/include/sys/user.h and +/usr/include/linux/mmzone.h to get PAGE_SIZE MAX_ORDER declarations. + +The pagesize can also be determined dynamically with the getpagesize (2) +system call. + + + Block number limit +-------------------- + +To understand the constraints of PACKET_MMAP, we have to see the structure +used to hold the pointers to each block. + +Currently, this structure is a dynamically allocated vector with kmalloc +called pg_vec, its size limits the number of blocks that can be allocated. + + +---+---+---+---+ + | x | x | x | x | + +---+---+---+---+ + | | | | + | | | v + | | v block #4 + | v block #3 + v block #2 + block #1 + + +kmalloc allocates any number of bytes of phisically contiguous memory from +a pool of pre-determined sizes. This pool of memory is mantained by the slab +allocator wich is at the end the responsible for doing the allocation and +hence wich imposes the maximum memory that kmalloc can allocate. + +In a 2.4/2.6 kernel and the i386 architecture, the limit is 131072 bytes. The +predetermined sizes that kmalloc uses can be checked in the "size-" +entries of /proc/slabinfo + +In a 32 bit architecture, pointers are 4 bytes long, so the total number of +pointers to blocks is + + 131072/4 = 32768 blocks + + + PACKET_MMAP buffer size calculator +------------------------------------ + +Definitions: + + : is the maximum size of allocable with kmalloc (see /proc/slabinfo) +: depends on the architecture -- sizeof(void *) + : depends on the architecture -- PAGE_SIZE or getpagesize (2) + : is the value defined with MAX_ORDER + : it's an upper bound of frame's capture size (more on this later) + +from these definitions we will derive + + = / + = << + +so, the max buffer size is + + * + +and, the number of frames be + + * / + +Suposse the following parameters, wich apply for 2.6 kernel and an +i386 architecture: + + = 131072 bytes + = 4 bytes + = 4096 bytes + = 11 + +and a value for of 2048 byteas. These parameters will yield + + = 131072/4 = 32768 blocks + = 4096 << 11 = 8 MiB. + +and hence the buffer will have a 262144 MiB size. So it can hold +262144 MiB / 2048 bytes = 134217728 frames + + +Actually, this buffer size is not possible with an i386 architecture. +Remember that the memory is allocated in kernel space, in the case of +an i386 kernel's memory size is limited to 1GiB. + +All memory allocations are not freed until the socket is closed. The memory +allocations are done with GFP_KERNEL priority, this basically means that +the allocation can wait and swap other process' memory in order to allocate +the nececessary memory, so normally limits can be reached. + + Other constraints +------------------- + +If you check the source code you will see that what I draw here as a frame +is not only the link level frame. At the begining of each frame there is a +header called struct tpacket_hdr used in PACKET_MMAP to hold link level's frame +meta information like timestamp. So what we draw here a frame it's really +the following (from include/linux/if_packet.h): + +/* + Frame structure: + + - Start. Frame must be aligned to TPACKET_ALIGNMENT=16 + - struct tpacket_hdr + - pad to TPACKET_ALIGNMENT=16 + - struct sockaddr_ll + - Gap, chosen so that packet data (Start+tp_net) alignes to + TPACKET_ALIGNMENT=16 + - Start+tp_mac: [ Optional MAC header ] + - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16. + - Pad to align to TPACKET_ALIGNMENT=16 + */ + + + The following are conditions that are checked in packet_set_ring + + tp_block_size must be a multiple of PAGE_SIZE (1) + tp_frame_size must be greater than TPACKET_HDRLEN (obvious) + tp_frame_size must be a multiple of TPACKET_ALIGNMENT + tp_frame_nr must be exactly frames_per_block*tp_block_nr + +Note that tp_block_size should be choosed to be a power of two or there will +be a waste of memory. + +-------------------------------------------------------------------------------- ++ Maping and use of the circular buffer (ring) +-------------------------------------------------------------------------------- + +The maping of the buffer in the user process is done with the conventional +mmap function. Even the circular buffer is compound of several physically +discontiguous blocks of memory, they are contiguous to the user space, hence +just one call to mmap is needed: + + mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + +If tp_frame_size is a divisor of tp_block_size frames will be +contiguosly spaced by tp_frame_size bytes. If not, each +tp_block_size/tp_frame_size frames there will be a gap between +the frames. This is because a frame cannot be spawn across two +blocks. + +At the beginning of each frame there is an status field (see +struct tpacket_hdr). If this field is 0 means that the frame is ready +to be used for the kernel, If not, there is a frame the user can read +and the following flags apply: + + from include/linux/if_packet.h + + #define TP_STATUS_COPY 2 + #define TP_STATUS_LOSING 4 + #define TP_STATUS_CSUMNOTREADY 8 + + +TP_STATUS_COPY : This flag indicates that the frame (and associated + meta information) has been truncated because it's + larger than tp_frame_size. This packet can be + read entirely with recvfrom(). + + In order to make this work it must to be + enabled previously with setsockopt() and + the PACKET_COPY_THRESH option. + + The number of frames than can be buffered to + be read with recvfrom is limited like a normal socket. + See the SO_RCVBUF option in the socket (7) man page. + +TP_STATUS_LOSING : indicates there were packet drops from last time + statistics where checked with getsockopt() and + the PACKET_STATISTICS option. + +TP_STATUS_CSUMNOTREADY: currently it's used for outgoing IP packets wich + it's checksum will be done in hardware. So while + reading the packet we should not try to check the + checksum. + +for convenience there are also the following defines: + + #define TP_STATUS_KERNEL 0 + #define TP_STATUS_USER 1 + +The kernel initializes all frames to TP_STATUS_KERNEL, when the kernel +receives a packet it puts in the buffer and updates the status with +at least the TP_STATUS_USER flag. Then the user can read the packet, +once the packet is read the user must zero the status field, so the kernel +can use again that frame buffer. + +The user can use poll (any other variant should apply too) to check if new +packets are in the ring: + + struct pollfd pfd; + + pfd.fd = fd; + pfd.revents = 0; + pfd.events = POLLIN|POLLRDNORM|POLLERR; + + if (status == TP_STATUS_KERNEL) + retval = poll(&pfd, 1, timeout); + +It doesn't incur in a race condition to first check the status value and +then poll for frames. + +-------------------------------------------------------------------------------- ++ THANKS +-------------------------------------------------------------------------------- + + Jesse Brandeburg, for fixing my grammathical/spelling errors + +>>> EOF +- +To unsubscribe from this list: send the line "unsubscribe linux-net" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff -urN linux-2.4.25/MAINTAINERS linux-2.4.26/MAINTAINERS --- linux-2.4.25/MAINTAINERS 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/MAINTAINERS 2004-04-14 06:05:25.000000000 -0700 @@ -166,7 +166,7 @@ P: Len Brown M: len.brown@intel.com L: acpi-devel@lists.sourceforge.net -W: http://sf.net/projects/acpi/ +W: http://acpi.sourceforge.net/ S: Maintained AD1816 SOUND DRIVER @@ -1081,8 +1081,8 @@ P: Andrew Stanley-Jones M: asj@lanmedia.com W: http://www.lanmedia.com/ -S: Supported - +S: Orphan + LAPB module P: Henner Eisen M: eis@baty.hanse.de @@ -1456,9 +1456,9 @@ PERMEDIA 3 FRAMEBUFFER DRIVER P: Romain Dolbeau -M: dolbeau@irisa.fr +M: dolbeau@caps-entreprise.com L: linux-fbdev-devel@lists.sourceforge.net -W: http://www.irisa.fr/prive/dolbeau/pm3fb/pm3fb.html +W: http://www.caps-entreprise.com/private/dolbeau/pm3fb/pm3fb.html S: Maintained PHILIPS NINO PALM PC @@ -1626,6 +1626,12 @@ L: linux-scsi@vger.kernel.org S: Maintained +SCTP PROTOCOL +P: Sridhar Samudrala +M: sri@us.ibm.com +L: lksctp-developers@lists.sourceforge.net +S: Supported + SCx200 CPU SUPPORT P: Christer Weinigel M: christer@weinigel.se @@ -2067,8 +2073,8 @@ S: Maintained USB SUBSYSTEM -P: Greg Kroah-Hartman -M: greg@kroah.com +P: Pete Zaitcev +M: zaitcev@redhat.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://www.linux-usb.org @@ -2104,7 +2110,6 @@ VIA 82Cxxx AUDIO DRIVER P: Jeff Garzik -L: linux-via@gtf.org S: Odd fixes VIA RHINE NETWORK DRIVER diff -urN linux-2.4.25/Makefile linux-2.4.26/Makefile --- linux-2.4.25/Makefile 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/Makefile 2004-04-14 06:05:41.000000000 -0700 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 25 +SUBLEVEL = 26 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -223,7 +223,8 @@ drivers/tc/lk201-map.c \ net/khttpd/make_times_h \ net/khttpd/times.h \ - submenu* + submenu* \ + drivers/ieee1394/oui.c # directories removed with 'make clean' CLEAN_DIRS = \ modules diff -urN linux-2.4.25/arch/alpha/lib/ev6-stxncpy.S linux-2.4.26/arch/alpha/lib/ev6-stxncpy.S --- linux-2.4.25/arch/alpha/lib/ev6-stxncpy.S 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.26/arch/alpha/lib/ev6-stxncpy.S 2004-04-14 06:05:25.000000000 -0700 @@ -365,7 +365,7 @@ andnot t2, t6, t12 # E : dest mask for a single word copy or t8, t10, t5 # E : test for end-of-count too - cmpbge zero, t2, t3 # E : + cmpbge zero, t12, t3 # E : cmoveq a2, t5, t8 # E : Latency=2, extra map slot nop # E : keep with cmoveq andnot t8, t3, t8 # E : (stall) diff -urN linux-2.4.25/arch/alpha/lib/stxncpy.S linux-2.4.26/arch/alpha/lib/stxncpy.S --- linux-2.4.25/arch/alpha/lib/stxncpy.S 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.26/arch/alpha/lib/stxncpy.S 2004-04-14 06:05:25.000000000 -0700 @@ -317,7 +317,7 @@ cmpbge zero, t1, t8 # .. e1 : is there a zero? andnot t2, t6, t12 # e0 : dest mask for a single word copy or t8, t10, t5 # .. e1 : test for end-of-count too - cmpbge zero, t2, t3 # e0 : + cmpbge zero, t12, t3 # e0 : cmoveq a2, t5, t8 # .. e1 : andnot t8, t3, t8 # e0 : beq t8, $u_head # .. e1 (zdb) diff -urN linux-2.4.25/arch/i386/defconfig linux-2.4.26/arch/i386/defconfig --- linux-2.4.25/arch/i386/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/defconfig 2004-04-14 06:05:25.000000000 -0700 @@ -2,7 +2,6 @@ # Automatically generated make config: don't edit # CONFIG_X86=y -CONFIG_ISA=y # CONFIG_SBUS is not set CONFIG_UID16=y @@ -31,12 +30,14 @@ # CONFIG_MPENTIUM4 is not set # CONFIG_MK6 is not set # CONFIG_MK7 is not set +# CONFIG_MK8 is not set # CONFIG_MELAN is not set # CONFIG_MCRUSOE is not set # CONFIG_MWINCHIPC6 is not set # CONFIG_MWINCHIP2 is not set # CONFIG_MWINCHIP3D is not set # CONFIG_MCYRIXIII is not set +# CONFIG_MVIAC3_2 is not set CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_CMPXCHG=y @@ -46,26 +47,29 @@ # CONFIG_RWSEM_GENERIC_SPINLOCK is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_X86_L1_CACHE_SHIFT=5 -CONFIG_X86_TSC=y +CONFIG_X86_HAS_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_F00F_WORKS_OK=y CONFIG_X86_MCE=y # CONFIG_TOSHIBA is not set # CONFIG_I8K is not set # CONFIG_MICROCODE is not set # CONFIG_X86_MSR is not set # CONFIG_X86_CPUID is not set -# CONFIG_EDD is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set +# CONFIG_HIGHMEM is not set # CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y -# CONFIG_MULTIQUAD is not set -CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=32 +# CONFIG_X86_NUMA is not set +# CONFIG_X86_TSC_DISABLE is not set +CONFIG_X86_TSC=y +CONFIG_HAVE_DEC_LOCK=y # # General setup @@ -79,6 +83,7 @@ CONFIG_PCI_GOANY=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y +CONFIG_ISA=y CONFIG_PCI_NAMES=y # CONFIG_EISA is not set # CONFIG_MCA is not set @@ -100,7 +105,6 @@ # CONFIG_HOTPLUG_PCI_COMPAQ is not set # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set # CONFIG_HOTPLUG_PCI_IBM is not set -# CONFIG_HOTPLUG_PCI_ACPI is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -109,10 +113,17 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +# CONFIG_OOM_KILLER is not set CONFIG_PM=y # CONFIG_APM is not set # +# ACPI Support +# +# CONFIG_ACPI is not set +CONFIG_ACPI_BOOT=y + +# # Memory Technology Devices (MTD) # # CONFIG_MTD is not set @@ -137,12 +148,14 @@ # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_STATS is not set # # Multi-device support (RAID and LVM) @@ -224,15 +237,6 @@ CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y # CONFIG_IDEDISK_STROKE is not set -# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set -# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set -# CONFIG_BLK_DEV_IDEDISK_IBM is not set -# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set -# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set -# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set -# CONFIG_BLK_DEV_IDEDISK_WD is not set -# CONFIG_BLK_DEV_COMMERIAL is not set -# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set @@ -246,8 +250,8 @@ CONFIG_BLK_DEV_CMD640=y # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set -CONFIG_BLK_DEV_RZ1000=y CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_GENERIC is not set CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set @@ -256,30 +260,29 @@ # CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set -CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_ADMA100 is not set # CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_AEC62XX_TUNING is not set # CONFIG_BLK_DEV_ALI15X3 is not set # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_BLK_DEV_CMD680 is not set +# CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set CONFIG_BLK_DEV_PIIX=y -CONFIG_PIIX_TUNING=y # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_PDC202XX is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_FORCE is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +CONFIG_BLK_DEV_RZ1000=y +# CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set @@ -291,6 +294,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set # # SCSI support @@ -325,12 +329,14 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_MEGARAID2 is not set # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set @@ -370,6 +376,7 @@ # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_NSP32 is not set # # PCMCIA SCSI adapter support @@ -429,16 +436,19 @@ # CONFIG_NET_ISA is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set +# CONFIG_B44 is not set # CONFIG_CS89x0 is not set # CONFIG_TULIP is not set -# CONFIG_TC35815 is not set # CONFIG_DE4X5 is not set # CONFIG_DGRS is not set # CONFIG_DM9102 is not set CONFIG_EEPRO100=y +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set # CONFIG_LNE390 is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set @@ -450,10 +460,11 @@ # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set -# CONFIG_8139_NEW_RX_RESET is not set +# CONFIG_8139_OLD_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_VIA_RHINE_MMIO is not set @@ -465,10 +476,12 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set +# CONFIG_E1000 is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set # CONFIG_FDDI is not set @@ -542,6 +555,7 @@ # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -583,13 +597,22 @@ # Input core support is needed for joysticks # # CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set # # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set # CONFIG_AMD_RNG is not set # CONFIG_INTEL_RNG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_AMD_PM768 is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set # CONFIG_DTLK is not set @@ -605,9 +628,16 @@ CONFIG_AGP_I810=y CONFIG_AGP_VIA=y CONFIG_AGP_AMD=y +# CONFIG_AGP_AMD_K8 is not set CONFIG_AGP_SIS=y CONFIG_AGP_ALI=y # CONFIG_AGP_SWORKS is not set +# CONFIG_AGP_NVIDIA is not set +# CONFIG_AGP_ATI is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# CONFIG_DRM=y # CONFIG_DRM_OLD is not set @@ -616,10 +646,12 @@ # CONFIG_DRM_NEW=y CONFIG_DRM_TDFX=y +# CONFIG_DRM_GAMMA is not set # CONFIG_DRM_R128 is not set CONFIG_DRM_RADEON=y CONFIG_DRM_I810=y CONFIG_DRM_I810_XFREE_41=y +# CONFIG_DRM_I830 is not set # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set @@ -627,7 +659,9 @@ # PCMCIA character devices # # CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_SYNCLINK_CS is not set # CONFIG_MWAVE is not set +# CONFIG_OBMOUSE is not set # # Multimedia devices @@ -638,6 +672,7 @@ # File systems # # CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set # CONFIG_AUTOFS_FS is not set CONFIG_AUTOFS4_FS=y # CONFIG_REISERFS_FS is not set @@ -647,6 +682,9 @@ # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set # CONFIG_BFS_FS is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set @@ -664,6 +702,9 @@ CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set @@ -683,6 +724,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -691,9 +737,11 @@ # CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set @@ -707,7 +755,6 @@ # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set # CONFIG_ZISOFS_FS is not set -# CONFIG_ZLIB_FS_INFLATE is not set # # Partition Types @@ -727,6 +774,7 @@ # Sound # CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set @@ -738,6 +786,7 @@ # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set # CONFIG_SOUND_ICH is not set # CONFIG_SOUND_RME96XX is not set # CONFIG_SOUND_SONICVIBES is not set @@ -748,6 +797,8 @@ # CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set +# CONFIG_SOUND_WM97XX is not set # # USB support @@ -760,7 +811,6 @@ # # CONFIG_USB_DEVICEFS is not set # CONFIG_USB_BANDWIDTH is not set -# CONFIG_USB_LONG_TIMEOUT is not set # # USB Host Controller Drivers @@ -768,13 +818,15 @@ # CONFIG_USB_EHCI_HCD is not set CONFIG_USB_UHCI_ALT=y # CONFIG_USB_OHCI is not set +# CONFIG_USB_SL811HS_ALT is not set +# CONFIG_USB_SL811HS is not set # # USB Device Class drivers # # CONFIG_USB_AUDIO is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_BLUETOOTH is not set +# CONFIG_USB_MIDI is not set CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set # CONFIG_USB_STORAGE_DATAFAB is not set @@ -783,6 +835,7 @@ # CONFIG_USB_STORAGE_DPCM is not set # CONFIG_USB_STORAGE_HP8200e is not set # CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set # CONFIG_USB_STORAGE_JUMPSHOT is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set @@ -799,7 +852,10 @@ # CONFIG_USB_HIDDEV is not set # CONFIG_USB_KBD is not set # CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set # # USB Imaging devices @@ -837,39 +893,20 @@ # USB Serial Converter support # # CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IPAQ is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_KLSI is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set # # USB Miscellaneous drivers # # CONFIG_USB_RIO500 is not set # CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_TIGL is not set # CONFIG_USB_BRLVGER is not set +# CONFIG_USB_LCD is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set # # Bluetooth support @@ -880,3 +917,16 @@ # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN linux-2.4.25/arch/i386/kernel/acpi.c linux-2.4.26/arch/i386/kernel/acpi.c --- linux-2.4.25/arch/i386/kernel/acpi.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/acpi.c 2004-04-14 06:05:25.000000000 -0700 @@ -49,14 +49,16 @@ #define PREFIX "ACPI: " -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; +int acpi_strict; +acpi_interrupt_flags acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ -#ifdef CONFIG_ACPI_BOOT int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ int acpi_ht __initdata = 1; /* enable HT */ @@ -214,6 +216,59 @@ return 0; } +/* + * Parse Interrupt Source Override for the ACPI SCI + */ +static void +acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) +{ + if (trigger == 0) /* compatible SCI trigger is level */ + trigger = 3; + + if (polarity == 0) /* compatible SCI polarity is low */ + polarity = 3; + + /* Command-line over-ride via acpi_sci= */ + if (acpi_sci_flags.trigger) + trigger = acpi_sci_flags.trigger; + + if (acpi_sci_flags.polarity) + polarity = acpi_sci_flags.polarity; + + /* + * mp_config_acpi_legacy_irqs() already setup IRQs < 16 + * If GSI is < 16, this will update its flags, + * else it will create a new mp_irqs[] entry. + */ + mp_override_legacy_irq(gsi, polarity, trigger, gsi); + + /* + * stash over-ride to indicate we've been here + * and for later update of acpi_fadt + */ + acpi_sci_override_gsi = gsi; + return; +} + +static int __init +acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt =0; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if (!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + +#ifdef CONFIG_ACPI_INTERPRETER + /* initialize sci_int early for INT_SRC_OVR MADT parsing */ + acpi_fadt.sci_int = fadt->sci_int; +#endif + + return 0; +} + static int __init acpi_parse_int_src_ovr ( @@ -227,6 +282,12 @@ acpi_table_print_madt_entry(header); + if (intsrc->bus_irq == acpi_fadt.sci_int) { + acpi_sci_ioapic_setup(intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); + return 0; + } + mp_override_legacy_irq ( intsrc->bus_irq, intsrc->flags.polarity, @@ -307,7 +368,7 @@ * acpi_lapic = 1 if LAPIC found * acpi_ioapic = 1 if IOAPIC found * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; - * if acpi_blacklisted() acpi_disabled = 1; + * if acpi_blacklisted() disable_acpi() * acpi_irq_model=... * ... * @@ -334,14 +395,14 @@ */ result = acpi_table_init(); if (result) { - acpi_disabled = 1; + disable_acpi(); return result; } result = acpi_blacklisted(); if (result) { printk(KERN_NOTICE PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - acpi_disabled = 1; + disable_acpi(); return result; } @@ -444,6 +505,9 @@ /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); + /* Record sci_int for use when looking for MADT sci_int override */ + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); @@ -451,6 +515,13 @@ return result; } + /* + * If BIOS did not supply an INT_SRC_OVR for the SCI + * pretend we got one so we can set the SCI flags. + */ + if (!acpi_sci_override_gsi) + acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); @@ -472,17 +543,15 @@ return 0; } -#endif /*CONFIG_ACPI_BOOT*/ #ifdef CONFIG_ACPI_BUS /* - * "acpi_pic_sci=level" (current default) - * programs the PIC-mode SCI to Level Trigger. - * (NO-OP if the BIOS set Level Trigger already) - * - * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's - * it may require Edge Trigger -- use "acpi_pic_sci=edge" - * (NO-OP if the BIOS set Edge Trigger already) + * acpi_pic_sci_set_trigger() + * + * use ELCR to set PIC-mode trigger type for SCI + * + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_sci=edge" * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. @@ -490,56 +559,41 @@ * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) */ -static __initdata int acpi_pic_sci_trigger; /* 0: level, 1: edge */ - void __init -acpi_pic_sci_set_trigger(unsigned int irq) +acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); - + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { printk(" Edge"); - if (!acpi_pic_sci_trigger) { + if (trigger == 3) { printk(" set to Level"); outb(val | mask, port); } } else { printk(" Level"); - if (acpi_pic_sci_trigger) { + if (trigger == 1) { printk(" set to Edge"); - outb(val | mask, port); + outb(val & ~mask, port); } } printk(" Trigger.\n"); } -int __init -acpi_pic_sci_setup(char *str) -{ - while (str && *str) { - if (strncmp(str, "level", 5) == 0) - acpi_pic_sci_trigger = 0; /* force level trigger */ - if (strncmp(str, "edge", 4) == 0) - acpi_pic_sci_trigger = 1; /* force edge trigger */ - str = strchr(str, ','); - if (str) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("acpi_pic_sci=", acpi_pic_sci_setup); - #endif /* CONFIG_ACPI_BUS */ +#ifndef __HAVE_ARCH_CMPXCHG +#warning ACPI uses CMPXCHG, i486 and later hardware +#endif + /* -------------------------------------------------------------------------- Low-Level Sleep Support -------------------------------------------------------------------------- */ @@ -656,7 +710,8 @@ void __init acpi_reserve_bootmem(void) { acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); - printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address); + if (!acpi_wakeup_address) + printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); } void do_suspend_lowlevel_s4bios(int resume) diff -urN linux-2.4.25/arch/i386/kernel/dmi_scan.c linux-2.4.26/arch/i386/kernel/dmi_scan.c --- linux-2.4.25/arch/i386/kernel/dmi_scan.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/dmi_scan.c 2004-04-14 06:05:25.000000000 -0700 @@ -482,13 +482,13 @@ #ifdef CONFIG_ACPI_BOOT -extern int acpi_disabled, acpi_force, acpi_ht; +extern int acpi_force; -static __init __attribute__((unused)) int acpi_disable(struct dmi_blacklist *d) +static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) { if (!acpi_force) { printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); - acpi_disabled = 1; + disable_acpi(); } else { printk(KERN_NOTICE "Warning: DMI blacklist says broken, but acpi forced\n"); @@ -504,7 +504,7 @@ { if (!acpi_force) { printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); - acpi_disabled = 1; + disable_acpi(); acpi_ht = 1; } else { printk(KERN_NOTICE @@ -839,7 +839,7 @@ * Boxes that need ACPI disabled */ - { acpi_disable, "IBM Thinkpad", { + { dmi_disable_acpi, "IBM Thinkpad", { MATCH(DMI_BOARD_VENDOR, "IBM"), MATCH(DMI_BOARD_NAME, "2629H1G"), NO_MATCH, NO_MATCH }}, @@ -968,8 +968,7 @@ if (disable && !acpi_force) { printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s); printk(KERN_NOTICE "You can enable it with acpi=force\n"); - acpi_disabled = 1; - acpi_ht = 0; + disable_acpi(); } } } diff -urN linux-2.4.25/arch/i386/kernel/i386_ksyms.c linux-2.4.26/arch/i386/kernel/i386_ksyms.c --- linux-2.4.25/arch/i386/kernel/i386_ksyms.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/i386_ksyms.c 2004-04-14 06:05:25.000000000 -0700 @@ -146,6 +146,10 @@ /* TLB flushing */ EXPORT_SYMBOL(flush_tlb_page); + +/* HT support */ +EXPORT_SYMBOL(smp_num_siblings); +EXPORT_SYMBOL(cpu_sibling_map); #endif #ifdef CONFIG_X86_IO_APIC diff -urN linux-2.4.25/arch/i386/kernel/io_apic.c linux-2.4.26/arch/i386/kernel/io_apic.c --- linux-2.4.25/arch/i386/kernel/io_apic.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/io_apic.c 2004-04-14 06:05:25.000000000 -0700 @@ -1864,7 +1864,11 @@ entry.trigger = edge_level; entry.polarity = active_high_low; - add_pin_to_irq(irq, ioapic, pin); + /* + * IRQs < 16 are already in the irq_2_pin[] map + */ + if (irq >= 16) + add_pin_to_irq(irq, ioapic, pin); entry.vector = assign_irq_vector(irq); diff -urN linux-2.4.25/arch/i386/kernel/microcode.c linux-2.4.26/arch/i386/kernel/microcode.c --- linux-2.4.25/arch/i386/kernel/microcode.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/microcode.c 2004-04-14 06:05:25.000000000 -0700 @@ -1,7 +1,7 @@ /* * Intel CPU Microcode Update driver for Linux * - * Copyright (C) 2000 Tigran Aivazian + * Copyright (C) 2000-2004 Tigran Aivazian * * This driver allows to upgrade microcode on Intel processors * belonging to IA-32 family - PentiumPro, Pentium II, @@ -64,6 +64,10 @@ * Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl * because we no longer hold a copy of applied microcode * in kernel memory. + * 1.14 23 Feb 2004 Tigran Aivazian + * Restored devfs regular file entry point which was + * accidentally removed when back-porting changes from the 2.6 + * version of the driver. */ @@ -73,6 +77,7 @@ #include #include #include +#include #include #include @@ -84,8 +89,8 @@ MODULE_AUTHOR("Tigran Aivazian "); MODULE_LICENSE("GPL"); -#define MICROCODE_VERSION "1.13" -#define MICRO_DEBUG 1 +#define MICROCODE_VERSION "1.14" +#define MICRO_DEBUG 0 #if MICRO_DEBUG #define dprintk(x...) printk(KERN_INFO x) #else @@ -470,6 +475,7 @@ return -EINVAL; } +/* shared between misc device and devfs regular file */ static struct file_operations microcode_fops = { .owner = THIS_MODULE, .write = microcode_write, @@ -483,29 +489,38 @@ .fops = µcode_fops, }; +static devfs_handle_t devfs_handle; + static int __init microcode_init (void) { int error; error = misc_register(µcode_dev); - if (error) { + if (error) printk(KERN_ERR "microcode: can't misc_register on minor=%d\n", MICROCODE_MINOR); - return error; + devfs_handle = devfs_register(NULL, "cpu/microcode", + DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, + µcode_fops, NULL); + if (devfs_handle == NULL && error) { + printk(KERN_ERR "microcode: failed to devfs_register()\n"); + goto out; } - + error = 0; printk(KERN_INFO - "IA-32 Microcode Update Driver: v%s \n", - MICROCODE_VERSION); - return 0; + "IA-32 Microcode Update Driver: v" + MICROCODE_VERSION " \n"); +out: + return error; } static void __exit microcode_exit (void) { misc_deregister(µcode_dev); - printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", - MICROCODE_VERSION); + devfs_unregister(devfs_handle); + printk(KERN_INFO "IA-32 Microcode Update Driver v" + MICROCODE_VERSION " unregistered\n"); } module_init(microcode_init) diff -urN linux-2.4.25/arch/i386/kernel/mpparse.c linux-2.4.26/arch/i386/kernel/mpparse.c --- linux-2.4.25/arch/i386/kernel/mpparse.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/mpparse.c 2004-04-14 06:05:25.000000000 -0700 @@ -34,6 +34,9 @@ /* Have we found an MP table */ int smp_found_config; +#ifdef CONFIG_SMP +extern unsigned int max_cpus; +#endif /* * Various Linux-internal data structures created from the @@ -229,11 +232,19 @@ boot_cpu_logical_apicid = logical_apicid; } - if (num_processors >= NR_CPUS){ - printk(KERN_WARNING "NR_CPUS limit of %i reached. Cannot " - "boot CPU(apicid 0x%x).\n", NR_CPUS, m->mpc_apicid); +#ifdef CONFIG_SMP + if (num_processors >= NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processor ignored.\n", NR_CPUS); + return; + } + if (num_processors >= max_cpus) { + printk(KERN_WARNING "WARNING: maxcpus limit of %i reached." + " Processor ignored.\n", max_cpus); return; } +#endif + num_processors++; if (m->mpc_apicid > MAX_APICS) { @@ -1118,7 +1129,7 @@ * erroneously sets the trigger to level, resulting in a HUGE * increase of timer interrupts! */ - if ((bus_irq == 0) && (global_irq == 2) && (trigger == 3)) + if ((bus_irq == 0) && (trigger == 3)) trigger = 1; intsrc.mpc_type = MP_INTSRC; @@ -1139,7 +1150,7 @@ * Otherwise create a new entry (e.g. global_irq == 2). */ for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) + if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { mp_irqs[i] = intsrc; found = 1; @@ -1200,13 +1211,14 @@ */ for (i = 0; i < 16; i++) { - if (i == 2) continue; /* Don't connect IRQ2 */ + if (i == 2) + continue; /* Don't connect IRQ2 */ mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC; mp_irqs[mp_irq_entries].mpc_irqflag = 0; /* Conforming */ mp_irqs[mp_irq_entries].mpc_srcbus = MP_ISA_BUS; mp_irqs[mp_irq_entries].mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; - mp_irqs[mp_irq_entries].mpc_irqtype = i ? mp_INT : mp_ExtINT; /* 8259A to #0 */ + mp_irqs[mp_irq_entries].mpc_irqtype = mp_INT; mp_irqs[mp_irq_entries].mpc_srcbusirq = i; /* Identity mapped */ mp_irqs[mp_irq_entries].mpc_dstirq = i; @@ -1227,70 +1239,6 @@ extern FADT_DESCRIPTOR acpi_fadt; -void __init mp_config_ioapic_for_sci(int irq) -{ - int ioapic; - int ioapic_pin; - struct acpi_table_madt* madt; - struct acpi_table_int_src_ovr *entry = NULL; - acpi_interrupt_flags flags; - void *madt_end; - acpi_status status; - - /* - * Ensure that if there is an interrupt source override entry - * for the ACPI SCI, we leave it as is. Unfortunately this involves - * walking the MADT again. - */ - status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) &madt); - if (ACPI_SUCCESS(status)) { - madt_end = (void *) (unsigned long)madt + madt->header.length; - - entry = (struct acpi_table_int_src_ovr *) - ((unsigned long) madt + sizeof(struct acpi_table_madt)); - - while ((void *) entry < madt_end) { - if (entry->header.type == ACPI_MADT_INT_SRC_OVR && - acpi_fadt.sci_int == entry->bus_irq) - goto found; - - entry = (struct acpi_table_int_src_ovr *) - ((unsigned long) entry + entry->header.length); - } - } - /* - * Although the ACPI spec says that the SCI should be level/low - * don't reprogram it unless there is an explicit MADT OVR entry - * instructing us to do so -- otherwise we break Tyan boards which - * have the SCI wired edge/high but no MADT OVR. - */ - return; - -found: - /* - * See the note at the end of ACPI 2.0b section - * 5.2.10.8 for what this is about. - */ - flags = entry->flags; - acpi_fadt.sci_int = entry->global_irq; - irq = entry->global_irq; - - ioapic = mp_find_ioapic(irq); - - ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - - /* - * MPS INTI flags: - * trigger: 0=default, 1=edge, 3=level - * polarity: 0=default, 1=high, 3=low - * Per ACPI spec, default for SCI means level/low. - */ - io_apic_set_pci_routing(ioapic, ioapic_pin, irq, - (flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1)); -} - - #ifdef CONFIG_ACPI_PCI void __init mp_parse_prt (void) @@ -1349,7 +1297,7 @@ continue; } if ((1<irq = irq; continue; diff -urN linux-2.4.25/arch/i386/kernel/pci-irq.c linux-2.4.26/arch/i386/kernel/pci-irq.c --- linux-2.4.25/arch/i386/kernel/pci-irq.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/pci-irq.c 2004-04-14 06:05:25.000000000 -0700 @@ -595,6 +595,7 @@ case PCI_DEVICE_ID_INTEL_82801E_0: case PCI_DEVICE_ID_INTEL_82801EB_0: case PCI_DEVICE_ID_INTEL_ESB_0: + case PCI_DEVICE_ID_INTEL_ICH6_0: r->name = "PIIX/ICH"; r->get = pirq_piix_get; r->set = pirq_piix_set; diff -urN linux-2.4.25/arch/i386/kernel/setup.c linux-2.4.26/arch/i386/kernel/setup.c --- linux-2.4.25/arch/i386/kernel/setup.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/setup.c 2004-04-14 06:05:25.000000000 -0700 @@ -187,6 +187,7 @@ #ifdef CONFIG_ACPI_BOOT extern int __initdata acpi_ht; int acpi_force __initdata = 0; +extern acpi_interrupt_flags acpi_sci_flags; #endif extern int blk_nohighio; @@ -831,27 +832,43 @@ } } } +#ifdef CONFIG_SMP + /* + * If the BIOS enumerates physical processors before logical, + * maxcpus=N at enumeration-time can be used to disable HT. + */ + else if (!memcmp(from, "maxcpus=", 8)) { + extern unsigned int max_cpus; + + max_cpus = simple_strtoul(from + 8, NULL, 0); + } +#endif #ifdef CONFIG_ACPI_BOOT /* "acpi=off" disables both ACPI table parsing and interpreter */ else if (!memcmp(from, "acpi=off", 8)) { - acpi_ht = 0; - acpi_disabled = 1; + disable_acpi(); } /* acpi=force to over-ride black-list */ else if (!memcmp(from, "acpi=force", 10)) { acpi_force = 1; - acpi_ht=1; + acpi_ht = 1; acpi_disabled = 0; } /* Limit ACPI to boot-time only, still enabled HT */ else if (!memcmp(from, "acpi=ht", 7)) { + if (!acpi_force) + disable_acpi(); acpi_ht = 1; - if (!acpi_force) acpi_disabled = 1; } + /* acpi=strict disables out-of-spec workarounds */ + else if (!memcmp(from, "acpi=strict", 11)) { + acpi_strict = 1; + } + else if (!memcmp(from, "pci=noacpi", 10)) { acpi_noirq_set(); } @@ -859,6 +876,16 @@ /* disable IO-APIC */ else if (!memcmp(from, "noapic", 6)) disable_ioapic_setup(); + + else if (!memcmp(from, "acpi_sci=edge", 13)) + acpi_sci_flags.trigger = 1; + else if (!memcmp(from, "acpi_sci=level", 14)) + acpi_sci_flags.trigger = 3; + else if (!memcmp(from, "acpi_sci=high", 13)) + acpi_sci_flags.polarity = 1; + else if (!memcmp(from, "acpi_sci=low", 12)) + acpi_sci_flags.polarity = 3; + #endif /* * highmem=size forces highmem to be exactly 'size' bytes. diff -urN linux-2.4.25/arch/i386/kernel/smpboot.c linux-2.4.26/arch/i386/kernel/smpboot.c --- linux-2.4.25/arch/i386/kernel/smpboot.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/i386/kernel/smpboot.c 2004-04-14 06:05:25.000000000 -0700 @@ -51,7 +51,7 @@ static int smp_b_stepping; /* Setup configured maximum number of CPUs to activate */ -static int max_cpus = NR_CPUS; +unsigned int max_cpus = NR_CPUS; /* Total count of live CPUs */ int smp_num_cpus = 1; @@ -77,10 +77,6 @@ * * Command-line option of "nosmp" or "maxcpus=0" will disable SMP * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . */ static int __init nosmp(char *str) @@ -91,14 +87,6 @@ __setup("nosmp", nosmp); -static int __init maxcpus(char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); - /* * Trampoline 80x86 program as an array. */ @@ -1120,8 +1108,6 @@ if (!(phys_cpu_present_map & apicid_to_phys_cpu_present(apicid))) continue; - if (max_cpus <= cpucount+1) - continue; do_boot_cpu(apicid); diff -urN linux-2.4.25/arch/i386/mm/init.c linux-2.4.26/arch/i386/mm/init.c --- linux-2.4.25/arch/i386/mm/init.c 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.26/arch/i386/mm/init.c 2004-04-14 06:05:25.000000000 -0700 @@ -510,7 +510,15 @@ if (!mem_map) BUG(); - +#ifdef CONFIG_HIGHMEM + /* check that fixmap and pkmap do not overlap */ + if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) { + printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n"); + printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n", + PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START); + BUG(); + } +#endif set_max_mapnr_init(); high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); diff -urN linux-2.4.25/arch/ia64/ia32/ia32_signal.c linux-2.4.26/arch/ia64/ia32/ia32_signal.c --- linux-2.4.25/arch/ia64/ia32/ia32_signal.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/ia32/ia32_signal.c 2004-04-14 06:05:25.000000000 -0700 @@ -615,7 +615,7 @@ return -EFAULT; } set_fs(KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, sigsetsize); set_fs(old_fs); if (ret >= 0 && uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) diff -urN linux-2.4.25/arch/ia64/kernel/Makefile linux-2.4.26/arch/ia64/kernel/Makefile --- linux-2.4.25/arch/ia64/kernel/Makefile 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/Makefile 2004-04-14 06:05:25.000000000 -0700 @@ -11,7 +11,7 @@ O_TARGET := kernel.o -export-objs := ia64_ksyms.o +export-objs := ia64_ksyms.o unwind.o obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o salinfo.o semaphore.o setup.o \ diff -urN linux-2.4.25/arch/ia64/kernel/acpi.c linux-2.4.26/arch/ia64/kernel/acpi.c --- linux-2.4.25/arch/ia64/kernel/acpi.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/acpi.c 2004-04-14 06:05:25.000000000 -0700 @@ -65,8 +65,6 @@ unsigned char acpi_kbd_controller_present = 1; -int acpi_disabled __initdata; /* XXX this shouldn't be needed---we can't boot without ACPI! */ - const char * acpi_get_sysname (void) { diff -urN linux-2.4.25/arch/ia64/kernel/ia64_ksyms.c linux-2.4.26/arch/ia64/kernel/ia64_ksyms.c --- linux-2.4.25/arch/ia64/kernel/ia64_ksyms.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/ia64_ksyms.c 2004-04-14 06:05:25.000000000 -0700 @@ -170,6 +170,8 @@ EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem); #endif +#ifdef CONFIG_ACPI #include extern acpi_status acpi_hp_csr_space(acpi_handle, u64 *, u64 *); EXPORT_SYMBOL(acpi_hp_csr_space); +#endif diff -urN linux-2.4.25/arch/ia64/kernel/mca.c linux-2.4.26/arch/ia64/kernel/mca.c --- linux-2.4.25/arch/ia64/kernel/mca.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/mca.c 2004-04-14 06:05:26.000000000 -0700 @@ -6,7 +6,7 @@ * Copyright (C) 2003 Hewlett-Packard Co * David Mosberger-Tang * - * Copyright (C) 2002 Dell Computer Corporation + * Copyright (C) 2002 Dell Inc. * Copyright (C) Matt Domsch (Matt_Domsch@dell.com) * * Copyright (C) 2002 Intel @@ -18,7 +18,7 @@ * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2004 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * * 03/04/15 D. Mosberger Added INIT backtrace support. @@ -40,6 +40,14 @@ * 2003-12-08 Keith Owens * smp_call_function() must not be called from interrupt context (can * deadlock on tasklist_lock). Use keventd to call smp_call_function(). + * + * 2004-02-01 Keith Owens + * Avoid deadlock when using printk() for MCA and INIT records. + * Delete all record printing code, moved to salinfo_decode in user space. + * Mark variables and functions static where possible. + * Delete dead variables and functions. + * Reorder to remove the need for forward declarations and to consolidate + * related code. */ #include #include @@ -67,9 +75,12 @@ #include #include -#undef MCA_PRT_XTRA_DATA +#if defined(IA64_MCA_DEBUG_INFO) +# define IA64_MCA_DEBUG(fmt...) printk(fmt) +#else +# define IA64_MCA_DEBUG(fmt...) +#endif -#define print_symbol(fmt, addr) printk(fmt, "(no symbol)"); extern void show_stack(struct task_struct *); typedef struct ia64_fptr { @@ -77,7 +88,7 @@ unsigned long gp; } ia64_fptr_t; -ia64_mc_info_t ia64_mc_info; +/* Used by mca_asm.S */ ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; u64 ia64_mca_proc_state_dump[512]; @@ -85,54 +96,17 @@ u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE/8] __attribute__((aligned(16))); -u64 ia64_os_mca_recovery_successful; u64 ia64_mca_serialize; -static void ia64_mca_wakeup_ipi_wait(void); -static void ia64_mca_wakeup(int cpu); -static void ia64_mca_wakeup_all(void); -static void ia64_log_init(int); + +/* In mca_asm.S */ extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); -static u64 ia64_log_get(int sal_info_type, u8 **buffer); -extern struct hw_interrupt_type irq_type_iosapic_level; - -struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; - -static struct irqaction cmci_irqaction = { - .handler = ia64_mca_cmc_int_handler, - .flags = SA_INTERRUPT, - .name = "cmc_hndlr" -}; - -static struct irqaction cmcp_irqaction = { - .handler = ia64_mca_cmc_int_caller, - .flags = SA_INTERRUPT, - .name = "cmc_poll" -}; - -static struct irqaction mca_rdzv_irqaction = { - .handler = ia64_mca_rendez_int_handler, - .flags = SA_INTERRUPT, - .name = "mca_rdzv" -}; -static struct irqaction mca_wkup_irqaction = { - .handler = ia64_mca_wakeup_int_handler, - .flags = SA_INTERRUPT, - .name = "mca_wkup" -}; +static ia64_mc_info_t ia64_mc_info; -static struct irqaction mca_cpe_irqaction = { - .handler = ia64_mca_cpe_int_handler, - .flags = SA_INTERRUPT, - .name = "cpe_hndlr" -}; +extern struct hw_interrupt_type irq_type_iosapic_level; -static struct irqaction mca_cpep_irqaction = { - .handler = ia64_mca_cpe_int_caller, - .flags = SA_INTERRUPT, - .name = "cpe_poll" -}; +struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ @@ -156,69 +130,163 @@ */ static int cpe_poll_enabled = 1; -extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size); +extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); static struct tq_struct cmc_disable_tq, cmc_enable_tq; /* + * IA64_MCA log support + */ +#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ +#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ + +typedef struct ia64_state_log_s +{ + spinlock_t isl_lock; + int isl_index; + unsigned long isl_count; + ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ +} ia64_state_log_t; + +static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; + +#define IA64_LOG_ALLOCATE(it, size) \ + {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size); \ + ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size);} +#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) +#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) +#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) +#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index +#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_INC(it) \ + {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \ + ia64_state_log[it].isl_count++;} +#define IA64_LOG_INDEX_DEC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) +#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) +#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count + +/* + * ia64_log_init + * Reset the OS ia64 log buffer + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * Outputs : None + */ +static void +ia64_log_init(int sal_info_type) +{ + u64 max_size = 0; + + IA64_LOG_NEXT_INDEX(sal_info_type) = 0; + IA64_LOG_LOCK_INIT(sal_info_type); + + // SAL will tell us the maximum size of any error record of this type + max_size = ia64_sal_get_state_info_size(sal_info_type); + if (!max_size) + /* alloc_bootmem() doesn't like zero-sized allocations! */ + return; + + // set up OS data structures to hold error info + IA64_LOG_ALLOCATE(sal_info_type, max_size); + memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); + memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); +} + +/* + * ia64_log_get + * + * Get the current MCA log from SAL and copy it into the OS log buffer. + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * irq_safe whether you can use printk at this point + * Outputs : size (total record length) + * *buffer (ptr to error record) + * + */ +static u64 +ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe) +{ + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + + IA64_LOG_LOCK(sal_info_type); + + /* Get the process state information */ + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); + + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + + if (total_len) { + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + if (irq_safe) { + IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. " + "Record length = %ld\n", __FUNCTION__, sal_info_type, total_len); + } + *buffer = (u8 *) log_buffer; + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + return 0; + } +} + +/* * ia64_mca_log_sal_error_record * - * This function retrieves a specified error record type from SAL, - * wakes up any processes waiting for error records, and sends it to - * the system log. + * This function retrieves a specified error record type from SAL + * and wakes up any processes waiting for error records. * * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) - * Outputs : platform error status */ -int -ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init) +static void +ia64_mca_log_sal_error_record(int sal_info_type) { u8 *buffer; u64 size; - int platform_err; + int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; + static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; - size = ia64_log_get(sal_info_type, &buffer); + size = ia64_log_get(sal_info_type, &buffer, irq_safe); if (!size) - return 0; + return; - /* TODO: - * 1. analyze error logs to determine recoverability - * 2. perform error recovery procedures, if applicable - * 3. set ia64_os_mca_recovery_successful flag, if applicable - */ + salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe); + + if (irq_safe) + printk(KERN_INFO "CPU %d: SAL log contains %s error record\n", + smp_processor_id(), + sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN"); - salinfo_log_wakeup(sal_info_type, buffer, size); - platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk); /* Clear logs from corrected errors in case there's no user-level logger */ if (sal_info_type == SAL_INFO_TYPE_CPE || sal_info_type == SAL_INFO_TYPE_CMC) ia64_sal_clear_state_info(sal_info_type); - - return platform_err; } /* * platform dependent error handling */ #ifndef PLATFORM_MCA_HANDLERS -void -mca_handler_platform (void) -{ - -} -void +static void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { - IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n", - smp_processor_id(), cpe_irq); + IA64_MCA_DEBUG("%s: received interrupt. CPU:%d vector = %#x\n", + __FUNCTION__, smp_processor_id(), cpe_irq); /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); } +#define print_symbol(fmt, addr) printk(fmt, "(no symbol)"); + static void show_min_state (pal_min_state_area_t *minstate) { @@ -357,7 +425,7 @@ PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31); } -void +static void init_handler_platform (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) { @@ -404,45 +472,7 @@ while (1); /* hang city if no debugger */ } -/* - * ia64_mca_init_platform - * - * External entry for platform specific MCA initialization. - * - * Inputs - * None - * - * Outputs - * None - */ -void -ia64_mca_init_platform (void) -{ - -} - -/* - * ia64_mca_check_errors - * - * External entry to check for error records which may have been posted by SAL - * for a prior failure. - * - * Inputs : None - * - * Outputs : None - */ -int -ia64_mca_check_errors (void) -{ - /* - * If there is an MCA error record pending, get it and log it. - */ - printk("CPU %d: checking for saved MCA error records\n", smp_processor_id()); - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1); - - return 0; -} - +#ifdef CONFIG_ACPI /* * ia64_mca_register_cpev * @@ -462,14 +492,15 @@ isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0); if (isrv.status) { - printk(KERN_ERR "ia64_mca_platform_init: failed to register Corrected " - "Platform Error interrupt vector with SAL.\n"); + printk(KERN_ERR "Failed to register Corrected Platform " + "Error interrupt vector with SAL (status %ld)\n", isrv.status); return; } - IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error " - "vector %#x setup and enabled\n", cpev); + IA64_MCA_DEBUG("%s: corrected platform error " + "vector %#x setup and enabled\n", __FUNCTION__, cpev); } +#endif /* CONFIG_ACPI */ #endif /* PLATFORM_MCA_HANDLERS */ @@ -495,12 +526,12 @@ cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x setup and enabled.\n", - smp_processor_id(), IA64_CMC_VECTOR); + __FUNCTION__, smp_processor_id(), IA64_CMC_VECTOR); - IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n", - smp_processor_id(), ia64_get_cmcv()); + IA64_MCA_DEBUG("%s: CPU %d CMCV = %#016lx\n", + __FUNCTION__, smp_processor_id(), ia64_get_cmcv()); } /* @@ -515,7 +546,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_vector_disable (void *dummy) { cmcv_reg_t cmcv; @@ -525,9 +556,9 @@ cmcv.cmcv_mask = 1; /* Mask/disable interrupt */ ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_cmc_vector_disable: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x disabled.\n", - smp_processor_id(), cmcv.cmcv_vector); + __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } /* @@ -542,7 +573,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_vector_enable (void *dummy) { cmcv_reg_t cmcv; @@ -552,63 +583,9 @@ cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_cmc_vector_enable: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x enabled.\n", - smp_processor_id(), cmcv.cmcv_vector); -} - - -#if defined(MCA_TEST) - -sal_log_processor_info_t slpi_buf; - -void -mca_test(void) -{ - slpi_buf.valid.psi_static_struct = 1; - slpi_buf.valid.num_cache_check = 1; - slpi_buf.valid.num_tlb_check = 1; - slpi_buf.valid.num_bus_check = 1; - slpi_buf.valid.processor_static_info.minstate = 1; - slpi_buf.valid.processor_static_info.br = 1; - slpi_buf.valid.processor_static_info.cr = 1; - slpi_buf.valid.processor_static_info.ar = 1; - slpi_buf.valid.processor_static_info.rr = 1; - slpi_buf.valid.processor_static_info.fr = 1; - - ia64_os_mca_dispatch(); -} - -#endif /* #if defined(MCA_TEST) */ - - -/* - * verify_guid - * - * Compares a test guid to a target guid and returns result. - * - * Inputs - * test_guid * (ptr to guid to be verified) - * target_guid * (ptr to standard guid to be verified against) - * - * Outputs - * 0 (test verifies against target) - * non-zero (test guid does not verify) - */ -static int -verify_guid (efi_guid_t *test, efi_guid_t *target) -{ - int rc; -#ifdef IA64_MCA_DEBUG_INFO - char out[40]; -#endif - - if ((rc = efi_guidcmp(*test, *target))) { - IA64_MCA_DEBUG(KERN_DEBUG - "verify_guid: invalid GUID = %s\n", - efi_guid_unparse(test, out)); - } - return rc; + __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } /* @@ -642,225 +619,39 @@ } /* - * ia64_mca_init - * - * Do all the system level mca specific initialization. - * - * 1. Register spinloop and wakeup request interrupt vectors - * - * 2. Register OS_MCA handler entry point - * - * 3. Register OS_INIT handler entry point - * - * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. + * ia64_mca_wakeup_ipi_wait * - * Note that this initialization is done very early before some kernel - * services are available. + * Wait for the inter-cpu interrupt to be sent by the + * monarch processor once it is done with handling the + * MCA. * * Inputs : None - * * Outputs : None */ -void __init -ia64_mca_init(void) +static void +ia64_mca_wakeup_ipi_wait(void) { - ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; - ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; - ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; - int i; - s64 rc; - struct ia64_sal_retval isrv; - u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ + int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); + int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); + u64 irr = 0; - IA64_MCA_DEBUG("ia64_mca_init: begin\n"); - - INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL); - INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL); - - /* initialize recovery success indicator */ - ia64_os_mca_recovery_successful = 0; - - /* Clear the Rendez checkin flag for all cpus */ - for(i = 0 ; i < NR_CPUS; i++) - ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - - /* - * Register the rendezvous spinloop and wakeup mechanism with SAL - */ - - /* Register the rendezvous interrupt vector with SAL */ - while (1) { - isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_VECTOR, - timeout, - SAL_MC_PARAM_RZ_ALWAYS); - rc = isrv.status; - if (rc == 0) - break; - if (rc == -2) { - printk(KERN_INFO "ia64_mca_init: increasing MCA rendezvous timeout from " - "%ld to %ld\n", timeout, isrv.v0); - timeout = isrv.v0; - continue; - } - printk(KERN_ERR "ia64_mca_init: Failed to register rendezvous interrupt " - "with SAL. rc = %ld\n", rc); - return; - } - - /* Register the wakeup interrupt vector with SAL */ - isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_VECTOR, - 0, 0); - rc = isrv.status; - if (rc) { - printk(KERN_ERR "ia64_mca_init: Failed to register wakeup interrupt with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - - ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); - /* - * XXX - disable SAL checksum by setting size to 0; should be - * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); - */ - ia64_mc_info.imi_mca_handler_size = 0; - - /* Register the os mca handler with SAL */ - if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, - ia64_mc_info.imi_mca_handler, - ia64_tpa(mca_hldlr_ptr->gp), - ia64_mc_info.imi_mca_handler_size, - 0, 0, 0))) - { - printk(KERN_ERR "ia64_mca_init: Failed to register os mca handler with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", - ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); - - /* - * XXX - disable SAL checksum by setting size to 0, should be - * IA64_INIT_HANDLER_SIZE - */ - ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); - ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); - ia64_mc_info.imi_slave_init_handler_size = 0; - - IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", - ia64_mc_info.imi_monarch_init_handler); - - /* Register the os init handler with SAL */ - if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, - ia64_mc_info.imi_monarch_init_handler, - ia64_tpa(ia64_get_gp()), - ia64_mc_info.imi_monarch_init_handler_size, - ia64_mc_info.imi_slave_init_handler, - ia64_tpa(ia64_get_gp()), - ia64_mc_info.imi_slave_init_handler_size))) - { - printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n"); - - /* - * Configure the CMCI/P vector and handler. Interrupts for CMC are - * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). - */ - register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); - register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction); - ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ - - /* Setup the MCA rendezvous interrupt vector */ - register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); - - /* Setup the MCA wakeup interrupt vector */ - register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); - - /* Setup the CPE interrupt vector */ - { - irq_desc_t *desc; - unsigned int irq; - int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); - - if (cpev >= 0) { - for (irq = 0; irq < NR_IRQS; ++irq) - if (irq_to_vector(irq) == cpev) { - desc = irq_desc(irq); - desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_iosapic_level; - setup_irq(irq, &mca_cpe_irqaction); - } - ia64_mca_register_cpev(cpev); - } - } - - /* Initialize the areas set aside by the OS to buffer the - * platform/processor error states for MCA/INIT/CMC - * handling. - */ - ia64_log_init(SAL_INFO_TYPE_MCA); - ia64_log_init(SAL_INFO_TYPE_INIT); - ia64_log_init(SAL_INFO_TYPE_CMC); - ia64_log_init(SAL_INFO_TYPE_CPE); - -#if defined(MCA_TEST) - mca_test(); -#endif /* #if defined(MCA_TEST) */ - - printk(KERN_INFO "Mca related initialization done\n"); - - /* commented out because this is done elsewhere */ -#if 0 - /* Do post-failure MCA error logging */ - ia64_mca_check_errors(); -#endif -} - -/* - * ia64_mca_wakeup_ipi_wait - * - * Wait for the inter-cpu interrupt to be sent by the - * monarch processor once it is done with handling the - * MCA. - * - * Inputs : None - * Outputs : None - */ -void -ia64_mca_wakeup_ipi_wait(void) -{ - int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); - int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); - u64 irr = 0; - - do { - switch(irr_num) { - case 0: - irr = ia64_get_irr0(); - break; - case 1: - irr = ia64_get_irr1(); - break; - case 2: - irr = ia64_get_irr2(); - break; - case 3: - irr = ia64_get_irr3(); - break; - } - } while (!(irr & (1UL << irr_bit))) ; -} + do { + switch(irr_num) { + case 0: + irr = ia64_get_irr0(); + break; + case 1: + irr = ia64_get_irr1(); + break; + case 2: + irr = ia64_get_irr2(); + break; + case 3: + irr = ia64_get_irr3(); + break; + } + } while (!(irr & (1UL << irr_bit))) ; +} /* * ia64_mca_wakeup @@ -871,7 +662,7 @@ * Inputs : cpuid * Outputs : None */ -void +static void ia64_mca_wakeup(int cpu) { platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); @@ -887,7 +678,7 @@ * Inputs : None * Outputs : None */ -void +static void ia64_mca_wakeup_all(void) { int cpu; @@ -912,7 +703,7 @@ * Inputs : None * Outputs : None */ -void +static void ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) { unsigned long flags; @@ -937,7 +728,6 @@ local_irq_restore(flags); } - /* * ia64_mca_wakeup_int_handler * @@ -953,7 +743,7 @@ * Outputs : None * */ -void +static void ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) { } @@ -972,11 +762,9 @@ * Outputs : None */ -void -ia64_return_to_sal_check(void) +static void +ia64_return_to_sal_check(int recover) { - pal_processor_state_info_t *psp = (pal_processor_state_info_t *) - &ia64_sal_to_os_handoff_state.proc_state_param; /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff @@ -987,15 +775,10 @@ ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - /* - * Did we correct the error? At the moment the only error that - * we fix is a TLB error, if any other kind of error occurred - * we must reboot. - */ - if (psp->cc == 1 && psp->bc == 1 && psp->rc == 1 && psp->uc == 1) - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; - else + if (recover) ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; + else + ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; /* Default = tell SAL to return to same context */ ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; @@ -1024,16 +807,12 @@ void ia64_mca_ucmc_handler(void) { - int platform_err = 0; + pal_processor_state_info_t *psp = (pal_processor_state_info_t *) + &ia64_sal_to_os_handoff_state.proc_state_param; + int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc); /* Get the MCA error record and log it */ - platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0); - - /* - * Do Platform-specific mca error handling if required. - */ - if (platform_err) - mca_handler_platform(); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); /* * Wakeup all the processors which are spinning in the rendezvous @@ -1042,7 +821,7 @@ ia64_mca_wakeup_all(); /* Return to SAL */ - ia64_return_to_sal_check(); + ia64_return_to_sal_check(recover); } /* @@ -1060,21 +839,21 @@ * Outputs * None */ -void +static void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) { static unsigned long cmc_history[CMC_HISTORY_LENGTH]; static int index; static spinlock_t cmc_history_lock = SPIN_LOCK_UNLOCKED; - IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n", - cmc_irq, smp_processor_id()); + IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", + __FUNCTION__, cmc_irq, smp_processor_id()); /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); spin_lock(&cmc_history_lock); if (!cmc_polling_enabled) { @@ -1098,7 +877,7 @@ * make sure there's a log somewhere that indicates * something is generating more than we can handle. */ - printk(KERN_WARNING "%s: WARNING: Switching to polling CMC handler, error records may be lost\n", __FUNCTION__); + printk(KERN_WARNING "WARNING: Switching to polling CMC handler; error records may be lost\n"); mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL); @@ -1114,41 +893,6 @@ } /* - * IA64_MCA log support - */ -#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ -#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ - -typedef struct ia64_state_log_s -{ - spinlock_t isl_lock; - int isl_index; - unsigned long isl_count; - ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ -} ia64_state_log_t; - -static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; - -#define IA64_LOG_ALLOCATE(it, size) \ - {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ - (ia64_err_rec_t *)alloc_bootmem(size); \ - ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ - (ia64_err_rec_t *)alloc_bootmem(size);} -#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) -#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) -#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) -#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index -#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index -#define IA64_LOG_INDEX_INC(it) \ - {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \ - ia64_state_log[it].isl_count++;} -#define IA64_LOG_INDEX_DEC(it) \ - ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index -#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) -#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) -#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count - -/* * ia64_mca_cmc_int_caller * * Triggered by sw interrupt from CMC polling routine. Calls @@ -1162,7 +906,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; @@ -1177,14 +921,14 @@ ia64_mca_cmc_int_handler(cpe_irq, arg, ptregs); for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); - + if (cpuid < NR_CPUS) { platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); } else { - /* If no log recored, switch out of polling mode */ + /* If no log record, switch out of polling mode */ if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { - printk(KERN_WARNING "%s: Returning to interrupt driven CMC handler\n", __FUNCTION__); + printk(KERN_WARNING "Returning to interrupt driven CMC handler\n"); schedule_task(&cmc_enable_tq); cmc_polling_enabled = 0; @@ -1227,7 +971,7 @@ * Outputs * None */ -void +static void ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; @@ -1279,57 +1023,26 @@ } /* - * ia64_mca_late_init + * C portion of the OS INIT handler * - * Opportunity to setup things that require initialization later - * than ia64_mca_init. Setup a timer to poll for CPEs if the - * platform doesn't support an interrupt driven mechanism. + * Called from ia64_monarch_init_handler + * + * Inputs: pointer to pt_regs where processor info was saved. + * + * Returns: + * 0 if SAL must warm boot the System + * 1 if SAL must return to interrupted context using PAL_MC_RESUME * - * Inputs : None - * Outputs : Status */ -static int __init -ia64_mca_late_init(void) +void +ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) { - init_timer(&cmc_poll_timer); - cmc_poll_timer.function = ia64_mca_cmc_poll; + pal_min_state_area_t *ms; - /* Reset to the correct state */ - cmc_polling_enabled = 0; + oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */ - init_timer(&cpe_poll_timer); - cpe_poll_timer.function = ia64_mca_cpe_poll; - - /* If platform doesn't support CPEI, get the timer going. */ - if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) { - register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); - ia64_mca_cpe_poll(0UL); - } - - return 0; -} - -module_init(ia64_mca_late_init); - -/* - * C portion of the OS INIT handler - * - * Called from ia64_monarch_init_handler - * - * Inputs: pointer to pt_regs where processor info was saved. - * - * Returns: - * 0 if SAL must warm boot the System - * 1 if SAL must return to interrupted context using PAL_MC_RESUME - * - */ -void -ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) -{ - pal_min_state_area_t *ms; - - printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", - ia64_sal_to_os_handoff_state.proc_state_param); + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", + ia64_sal_to_os_handoff_state.proc_state_param); /* * Address of minstate area provided by PAL is physical, @@ -1341,1080 +1054,259 @@ init_handler_platform(ms, pt, sw); /* call platform specific routines */ } -/* - * ia64_log_prt_guid - * - * Print a formatted GUID. - * - * Inputs : p_guid (ptr to the GUID) - * prfunc (print function) - * Outputs : None - * - */ -void -ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) -{ - char out[40]; - printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out)); -} - -static void -ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc) +static int __init +ia64_mca_disable_cpe_polling(char *str) { - unsigned long i; - int j; - - if (!p) - return; - - for (i = 0; i < n_ch;) { - prfunc("%p ", (void *)p); - for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) { - prfunc("%02x ", *p); - } - prfunc("\n"); - } + cpe_poll_enabled = 0; + return 1; } -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL +__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); -static void -ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc) -{ - prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n", - (void *)rh, sizeof(sal_log_record_header_t)); - ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t), - (prfunc_t)prfunc); - prfunc("Total record length = %d\n", rh->len); - ia64_log_prt_guid(&rh->platform_guid, prfunc); - prfunc("End of SAL RECORD HEADER\n"); -} +static struct irqaction cmci_irqaction = { + .handler = ia64_mca_cmc_int_handler, + .flags = SA_INTERRUPT, + .name = "cmc_hndlr" +}; -static void -ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc) -{ - prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n", - (void *)sh, sizeof(sal_log_section_hdr_t)); - ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t), - (prfunc_t)prfunc); - prfunc("Length of section & header = %d\n", sh->len); - ia64_log_prt_guid(&sh->guid, prfunc); - prfunc("End of SAL SECTION HEADER\n"); -} -#endif // MCA_PRT_XTRA_DATA for test only @FVL +static struct irqaction cmcp_irqaction = { + .handler = ia64_mca_cmc_int_caller, + .flags = SA_INTERRUPT, + .name = "cmc_poll" +}; -/* - * ia64_log_init - * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * Outputs : None - */ -void -ia64_log_init(int sal_info_type) -{ - u64 max_size = 0; +static struct irqaction mca_rdzv_irqaction = { + .handler = ia64_mca_rendez_int_handler, + .flags = SA_INTERRUPT, + .name = "mca_rdzv" +}; - IA64_LOG_NEXT_INDEX(sal_info_type) = 0; - IA64_LOG_LOCK_INIT(sal_info_type); +static struct irqaction mca_wkup_irqaction = { + .handler = ia64_mca_wakeup_int_handler, + .flags = SA_INTERRUPT, + .name = "mca_wkup" +}; - // SAL will tell us the maximum size of any error record of this type - max_size = ia64_sal_get_state_info_size(sal_info_type); +#ifdef CONFIG_ACPI +static struct irqaction mca_cpe_irqaction = { + .handler = ia64_mca_cpe_int_handler, + .flags = SA_INTERRUPT, + .name = "cpe_hndlr" +}; - // set up OS data structures to hold error info - IA64_LOG_ALLOCATE(sal_info_type, max_size); - memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); - memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); -} +static struct irqaction mca_cpep_irqaction = { + .handler = ia64_mca_cpe_int_caller, + .flags = SA_INTERRUPT, + .name = "cpe_poll" +}; +#endif /* CONFIG_ACPI */ /* - * ia64_log_get + * ia64_mca_init * - * Get the current MCA log from SAL and copy it into the OS log buffer. + * Do all the system level mca specific initialization. * - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * Outputs : size (total record length) - * *buffer (ptr to error record) + * 1. Register spinloop and wakeup request interrupt vectors * - */ -u64 -ia64_log_get(int sal_info_type, u8 **buffer) -{ - sal_log_record_header_t *log_buffer; - u64 total_len = 0; - int s; - - IA64_LOG_LOCK(sal_info_type); - - /* Get the process state information */ - log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); - - total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); - - if (total_len) { - IA64_LOG_INDEX_INC(sal_info_type); - IA64_LOG_UNLOCK(sal_info_type); - IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. " - "Record length = %ld\n", sal_info_type, total_len); - *buffer = (u8 *) log_buffer; - return total_len; - } else { - IA64_LOG_UNLOCK(sal_info_type); - return 0; - } -} - -/* - * ia64_log_prt_oem_data + * 2. Register OS_MCA handler entry point * - * Print OEM specific data if included. + * 3. Register OS_INIT handler entry point * - * Inputs : header_len (length passed in section header) - * sect_len (default length of section type) - * p_data (ptr to data) - * prfunc (print function) - * Outputs : None + * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * - */ -void -ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) -{ - int oem_data_len, i; - - if ((oem_data_len = header_len - sect_len) > 0) { - prfunc(" OEM Specific Data:"); - for (i = 0; i < oem_data_len; i++, p_data++) - prfunc(" %02x", *p_data); - } - prfunc("\n"); -} - -/* - * ia64_log_rec_header_print + * Note that this initialization is done very early before some kernel + * services are available. * - * Log info from the SAL error record header. + * Inputs : None * - * Inputs : lh * (ptr to SAL log error record header) - * prfunc (fn ptr of log output function to use) * Outputs : None */ -void -ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc) -{ - prfunc("+Err Record ID: %ld SAL Rev: %2x.%02x\n", lh->id, - lh->revision.major, lh->revision.minor); - prfunc("+Time: %02x/%02x/%02x%02x %02x:%02x:%02x Severity %d\n", - lh->timestamp.slh_month, lh->timestamp.slh_day, - lh->timestamp.slh_century, lh->timestamp.slh_year, - lh->timestamp.slh_hour, lh->timestamp.slh_minute, - lh->timestamp.slh_second, lh->severity); -} - -/* - * ia64_log_processor_regs_print - * Print the contents of the saved processor register(s) in the format - * [] - * - * Inputs : regs (Register save buffer) - * reg_num (# of registers) - * reg_class (application/banked/control/bank1_general) - * reg_prefix (ar/br/cr/b1_gr) - * Outputs : None - * - */ -void -ia64_log_processor_regs_print(u64 *regs, - int reg_num, - char *reg_class, - char *reg_prefix, - prfunc_t prfunc) -{ - int i; - - prfunc("+%s Registers\n", reg_class); - for (i = 0; i < reg_num; i++) - prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]); -} - -/* - * ia64_log_processor_fp_regs_print - * Print the contents of the saved floating page register(s) in the format - * [] - * - * Inputs: ia64_fpreg (Register save buffer) - * reg_num (# of registers) - * reg_class (application/banked/control/bank1_general) - * reg_prefix (ar/br/cr/b1_gr) - * Outputs: None - * - */ -void -ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs, - int reg_num, - char *reg_class, - char *reg_prefix, - prfunc_t prfunc) +void __init +ia64_mca_init(void) { + ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; + ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; + ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; + s64 rc; + struct ia64_sal_retval isrv; + u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ - prfunc("+%s Registers\n", reg_class); - for (i = 0; i < reg_num; i++) - prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1], - regs[i].u.bits[0]); -} - -static char *pal_mesi_state[] = { - "Invalid", - "Shared", - "Exclusive", - "Modified", - "Reserved1", - "Reserved2", - "Reserved3", - "Reserved4" -}; - -static char *pal_cache_op[] = { - "Unknown", - "Move in", - "Cast out", - "Coherency check", - "Internal", - "Instruction fetch", - "Implicit Writeback", - "Reserved" -}; - -/* - * ia64_log_cache_check_info_print - * Display the machine check information related to cache error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * cc_info * (Ptr to cache check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_cache_check_info_print (int i, - sal_log_mod_error_info_t *cache_check_info, - prfunc_t prfunc) -{ - pal_cache_check_info_t *info; - u64 target_addr; - - if (!cache_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i); - return; /* If check info data not valid, skip it */ - } - - info = (pal_cache_check_info_t *)&cache_check_info->check_info; - target_addr = cache_check_info->target_identifier; - - prfunc("+ Cache check info[%d]\n+", i); - prfunc(" Level: L%d,",info->level); - if (info->mv) - prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]); - prfunc(" Index: %d,", info->index); - if (info->ic) - prfunc(" Cache: Instruction,"); - if (info->dc) - prfunc(" Cache: Data,"); - if (info->tl) - prfunc(" Line: Tag,"); - if (info->dl) - prfunc(" Line: Data,"); - prfunc(" Operation: %s,", pal_cache_op[info->op]); - if (info->wiv) - prfunc(" Way: %d,", info->way); - if (cache_check_info->valid.target_identifier) - /* Hope target address is saved in target_identifier */ - if (info->tv) - prfunc(" Target Addr: 0x%lx,", target_addr); - if (info->mcc) - prfunc(" MC: Corrected"); - prfunc("\n"); -} - -/* - * ia64_log_tlb_check_info_print - * Display the machine check information related to tlb error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * tlb_info * (Ptr to machine check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_tlb_check_info_print (int i, - sal_log_mod_error_info_t *tlb_check_info, - prfunc_t prfunc) - -{ - pal_tlb_check_info_t *info; - - if (!tlb_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i); - return; /* If check info data not valid, skip it */ - } - - info = (pal_tlb_check_info_t *)&tlb_check_info->check_info; - - prfunc("+ TLB Check Info [%d]\n+", i); - if (info->itc) - prfunc(" Failure: Instruction Translation Cache"); - if (info->dtc) - prfunc(" Failure: Data Translation Cache"); - if (info->itr) { - prfunc(" Failure: Instruction Translation Register"); - prfunc(" ,Slot: %ld", info->tr_slot); - } - if (info->dtr) { - prfunc(" Failure: Data Translation Register"); - prfunc(" ,Slot: %ld", info->tr_slot); - } - if (info->mcc) - prfunc(" ,MC: Corrected"); - prfunc("\n"); -} - -/* - * ia64_log_bus_check_info_print - * Display the machine check information related to bus error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * bus_info * (Ptr to machine check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_bus_check_info_print (int i, - sal_log_mod_error_info_t *bus_check_info, - prfunc_t prfunc) -{ - pal_bus_check_info_t *info; - u64 req_addr; /* Address of the requestor of the transaction */ - u64 resp_addr; /* Address of the responder of the transaction */ - u64 targ_addr; /* Address where the data was to be delivered to */ - /* or obtained from */ - - if (!bus_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i); - return; /* If check info data not valid, skip it */ - } + IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); - info = (pal_bus_check_info_t *)&bus_check_info->check_info; - req_addr = bus_check_info->requestor_identifier; - resp_addr = bus_check_info->responder_identifier; - targ_addr = bus_check_info->target_identifier; - - prfunc("+ BUS Check Info [%d]\n+", i); - prfunc(" Status Info: %d", info->bsi); - prfunc(" ,Severity: %d", info->sev); - prfunc(" ,Transaction Type: %d", info->type); - prfunc(" ,Transaction Size: %d", info->size); - if (info->cc) - prfunc(" ,Cache-cache-transfer"); - if (info->ib) - prfunc(" ,Error: Internal"); - if (info->eb) - prfunc(" ,Error: External"); - if (info->mcc) - prfunc(" ,MC: Corrected"); - if (info->tv) - prfunc(" ,Target Address: 0x%lx", targ_addr); - if (info->rq) - prfunc(" ,Requestor Address: 0x%lx", req_addr); - if (info->tv) - prfunc(" ,Responder Address: 0x%lx", resp_addr); - prfunc("\n"); -} + INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL); + INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL); -/* - * ia64_log_mem_dev_err_info_print - * - * Format and log the platform memory device error record section data. - * - * Inputs: mem_dev_err_info * (Ptr to memory device error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei, - prfunc_t prfunc) -{ - prfunc("+ Mem Error Detail: "); + /* Clear the Rendez checkin flag for all cpus */ + for(i = 0 ; i < NR_CPUS; i++) + ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - if (mdei->valid.error_status) - prfunc(" Error Status: %#lx,", mdei->error_status); - if (mdei->valid.physical_addr) - prfunc(" Physical Address: %#lx,", mdei->physical_addr); - if (mdei->valid.addr_mask) - prfunc(" Address Mask: %#lx,", mdei->addr_mask); - if (mdei->valid.node) - prfunc(" Node: %d,", mdei->node); - if (mdei->valid.card) - prfunc(" Card: %d,", mdei->card); - if (mdei->valid.module) - prfunc(" Module: %d,", mdei->module); - if (mdei->valid.bank) - prfunc(" Bank: %d,", mdei->bank); - if (mdei->valid.device) - prfunc(" Device: %d,", mdei->device); - if (mdei->valid.row) - prfunc(" Row: %d,", mdei->row); - if (mdei->valid.column) - prfunc(" Column: %d,", mdei->column); - if (mdei->valid.bit_position) - prfunc(" Bit Position: %d,", mdei->bit_position); - if (mdei->valid.target_id) - prfunc(" ,Target Address: %#lx,", mdei->target_id); - if (mdei->valid.requestor_id) - prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id); - if (mdei->valid.responder_id) - prfunc(" ,Responder Address: %#lx,", mdei->responder_id); - if (mdei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data); - prfunc("\n"); - - if (mdei->valid.oem_id) { - u8 *p_data = &(mdei->oem_id[0]); - int i; - - prfunc(" OEM Memory Controller ID:"); - for (i = 0; i < 16; i++, p_data++) - prfunc(" %02x", *p_data); - prfunc("\n"); - } + /* + * Register the rendezvous spinloop and wakeup mechanism with SAL + */ - if (mdei->valid.oem_data) { - platform_mem_dev_err_print((int)mdei->header.len, - (int)sizeof(sal_log_mem_dev_err_info_t) - 1, - &(mdei->oem_data[0]), prfunc); + /* Register the rendezvous interrupt vector with SAL */ + while (1) { + isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_RENDEZ_VECTOR, + timeout, + SAL_MC_PARAM_RZ_ALWAYS); + rc = isrv.status; + if (rc == 0) + break; + if (rc == -2) { + printk(KERN_INFO "Increasing MCA rendezvous timeout from " + "%ld to %ld milliseconds\n", timeout, isrv.v0); + timeout = isrv.v0; + continue; + } + printk(KERN_ERR "Failed to register rendezvous interrupt " + "with SAL (status %ld)\n", rc); + return; } -} -/* - * ia64_log_sel_dev_err_info_print - * - * Format and log the platform SEL device error record section data. - * - * Inputs: sel_dev_err_info * (Ptr to the SEL device error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei, - prfunc_t prfunc) -{ - int i; - - prfunc("+ SEL Device Error Detail: "); - - if (sdei->valid.record_id) - prfunc(" Record ID: %#x", sdei->record_id); - if (sdei->valid.record_type) - prfunc(" Record Type: %#x", sdei->record_type); - prfunc(" Time Stamp: "); - for (i = 0; i < 4; i++) - prfunc("%1d", sdei->timestamp[i]); - if (sdei->valid.generator_id) - prfunc(" Generator ID: %#x", sdei->generator_id); - if (sdei->valid.evm_rev) - prfunc(" Message Format Version: %#x", sdei->evm_rev); - if (sdei->valid.sensor_type) - prfunc(" Sensor Type: %#x", sdei->sensor_type); - if (sdei->valid.sensor_num) - prfunc(" Sensor Number: %#x", sdei->sensor_num); - if (sdei->valid.event_dir) - prfunc(" Event Direction Type: %#x", sdei->event_dir); - if (sdei->valid.event_data1) - prfunc(" Data1: %#x", sdei->event_data1); - if (sdei->valid.event_data2) - prfunc(" Data2: %#x", sdei->event_data2); - if (sdei->valid.event_data3) - prfunc(" Data3: %#x", sdei->event_data3); - prfunc("\n"); - -} - -/* - * ia64_log_pci_bus_err_info_print - * - * Format and log the platform PCI bus error record section data. - * - * Inputs: pci_bus_err_info * (Ptr to the PCI bus error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei, - prfunc_t prfunc) -{ - prfunc("+ PCI Bus Error Detail: "); - - if (pbei->valid.err_status) - prfunc(" Error Status: %#lx", pbei->err_status); - if (pbei->valid.err_type) - prfunc(" Error Type: %#x", pbei->err_type); - if (pbei->valid.bus_id) - prfunc(" Bus ID: %#x", pbei->bus_id); - if (pbei->valid.bus_address) - prfunc(" Bus Address: %#lx", pbei->bus_address); - if (pbei->valid.bus_data) - prfunc(" Bus Data: %#lx", pbei->bus_data); - if (pbei->valid.bus_cmd) - prfunc(" Bus Command: %#lx", pbei->bus_cmd); - if (pbei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", pbei->requestor_id); - if (pbei->valid.responder_id) - prfunc(" Responder ID: %#lx", pbei->responder_id); - if (pbei->valid.target_id) - prfunc(" Target ID: %#lx", pbei->target_id); - if (pbei->valid.oem_data) - prfunc("\n"); - - if (pbei->valid.oem_data) { - platform_pci_bus_err_print((int)pbei->header.len, - (int)sizeof(sal_log_pci_bus_err_info_t) - 1, - &(pbei->oem_data[0]), prfunc); + /* Register the wakeup interrupt vector with SAL */ + isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_WAKEUP_VECTOR, + 0, 0); + rc = isrv.status; + if (rc) { + printk(KERN_ERR "Failed to register wakeup interrupt with SAL " + "(status %ld)\n", rc); + return; } -} -/* - * ia64_log_smbios_dev_err_info_print - * - * Format and log the platform SMBIOS device error record section data. - * - * Inputs: smbios_dev_err_info * (Ptr to the SMBIOS device error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei, - prfunc_t prfunc) -{ - u8 i; + IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__); - prfunc("+ SMBIOS Device Error Detail: "); - - if (sdei->valid.event_type) - prfunc(" Event Type: %#x", sdei->event_type); - if (sdei->valid.time_stamp) { - prfunc(" Time Stamp: "); - for (i = 0; i < 6; i++) - prfunc("%d", sdei->time_stamp[i]); - } - if ((sdei->valid.data) && (sdei->valid.length)) { - prfunc(" Data: "); - for (i = 0; i < sdei->length; i++) - prfunc(" %02x", sdei->data[i]); - } - prfunc("\n"); -} + ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); + /* + * XXX - disable SAL checksum by setting size to 0; should be + * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); + */ + ia64_mc_info.imi_mca_handler_size = 0; -/* - * ia64_log_pci_comp_err_info_print - * - * Format and log the platform PCI component error record section data. - * - * Inputs: pci_comp_err_info * (Ptr to the PCI component error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei, - prfunc_t prfunc) -{ - u32 n_mem_regs, n_io_regs; - u64 i, n_pci_data; - u64 *p_reg_data; - u8 *p_oem_data; - - prfunc("+ PCI Component Error Detail: "); - - if (pcei->valid.err_status) - prfunc(" Error Status: %#lx\n", pcei->err_status); - if (pcei->valid.comp_info) - prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x," - " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n", - pcei->comp_info.vendor_id, pcei->comp_info.device_id, - pcei->comp_info.class_code, pcei->comp_info.seg_num, - pcei->comp_info.bus_num, pcei->comp_info.dev_num, - pcei->comp_info.func_num); - - n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0; - n_io_regs = (pcei->valid.num_io_regs) ? pcei->num_io_regs : 0; - p_reg_data = &(pcei->reg_data_pairs[0]); - p_oem_data = (u8 *)p_reg_data + - (n_mem_regs + n_io_regs) * 2 * sizeof(u64); - n_pci_data = p_oem_data - (u8 *)pcei; - - if (n_pci_data > pcei->header.len) { - prfunc(" Invalid PCI Component Error Record format: length = %ld, " - " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n", - pcei->header.len, n_pci_data, n_mem_regs, n_io_regs); + /* Register the os mca handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, + ia64_mc_info.imi_mca_handler, + ia64_tpa(mca_hldlr_ptr->gp), + ia64_mc_info.imi_mca_handler_size, + 0, 0, 0))) + { + printk(KERN_ERR "Failed to register OS MCA handler with SAL " + "(status %ld)\n", rc); return; } - if (n_mem_regs) { - prfunc(" Memory Mapped Registers\n Address \tValue\n"); - for (i = 0; i < pcei->num_mem_regs; i++) { - prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); - p_reg_data += 2; - } - } - if (n_io_regs) { - prfunc(" I/O Mapped Registers\n Address \tValue\n"); - for (i = 0; i < pcei->num_io_regs; i++) { - prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); - p_reg_data += 2; - } - } - if (pcei->valid.oem_data) { - platform_pci_comp_err_print((int)pcei->header.len, n_pci_data, - p_oem_data, prfunc); - prfunc("\n"); - } -} - -/* - * ia64_log_plat_specific_err_info_print - * - * Format and log the platform specifie error record section data. - * - * Inputs: sel_dev_err_info * (Ptr to the platform specific error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei, - prfunc_t prfunc) -{ - prfunc("+ Platform Specific Error Detail: "); + IA64_MCA_DEBUG("%s: registered OS MCA handler with SAL at 0x%lx, gp = 0x%lx\n", __FUNCTION__, + ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); - if (psei->valid.err_status) - prfunc(" Error Status: %#lx", psei->err_status); - if (psei->valid.guid) { - prfunc(" GUID: "); - ia64_log_prt_guid(&psei->guid, prfunc); - } - if (psei->valid.oem_data) { - platform_plat_specific_err_print((int) psei->header.len, - (char *) psei->oem_data - (char *) psei, - &psei->oem_data[0], prfunc); - } - prfunc("\n"); -} + /* + * XXX - disable SAL checksum by setting size to 0, should be + * size of the actual init handler in mca_asm.S. + */ + ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler_size = 0; + ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler_size = 0; -/* - * ia64_log_host_ctlr_err_info_print - * - * Format and log the platform host controller error record section data. - * - * Inputs: host_ctlr_err_info * (Ptr to the host controller error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei, - prfunc_t prfunc) -{ - prfunc("+ Host Controller Error Detail: "); + IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__, + ia64_mc_info.imi_monarch_init_handler); - if (hcei->valid.err_status) - prfunc(" Error Status: %#lx", hcei->err_status); - if (hcei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", hcei->requestor_id); - if (hcei->valid.responder_id) - prfunc(" Responder ID: %#lx", hcei->responder_id); - if (hcei->valid.target_id) - prfunc(" Target ID: %#lx", hcei->target_id); - if (hcei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data); - if (hcei->valid.oem_data) { - platform_host_ctlr_err_print((int)hcei->header.len, - (int)sizeof(sal_log_host_ctlr_err_info_t) - 1, - &(hcei->oem_data[0]), prfunc); + /* Register the os init handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, + ia64_mc_info.imi_monarch_init_handler, + ia64_tpa(ia64_get_gp()), + ia64_mc_info.imi_monarch_init_handler_size, + ia64_mc_info.imi_slave_init_handler, + ia64_tpa(ia64_get_gp()), + ia64_mc_info.imi_slave_init_handler_size))) + { + printk(KERN_ERR "Failed to register m/s INIT handlers with SAL " + "(status %ld)\n", rc); + return; } - prfunc("\n"); -} -/* - * ia64_log_plat_bus_err_info_print - * - * Format and log the platform bus error record section data. - * - * Inputs: plat_bus_err_info * (Ptr to the platform bus error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei, - prfunc_t prfunc) -{ - prfunc("+ Platform Bus Error Detail: "); + IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); - if (pbei->valid.err_status) - prfunc(" Error Status: %#lx", pbei->err_status); - if (pbei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", pbei->requestor_id); - if (pbei->valid.responder_id) - prfunc(" Responder ID: %#lx", pbei->responder_id); - if (pbei->valid.target_id) - prfunc(" Target ID: %#lx", pbei->target_id); - if (pbei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data); - if (pbei->valid.oem_data) { - platform_plat_bus_err_print((int)pbei->header.len, - (int)sizeof(sal_log_plat_bus_err_info_t) - 1, - &(pbei->oem_data[0]), prfunc); - } - prfunc("\n"); -} + /* + * Configure the CMCI/P vector and handler. Interrupts for CMC are + * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). + */ + register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); + register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction); + ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ -/* - * ia64_log_proc_dev_err_info_print - * - * Display the processor device error record. - * - * Inputs: sal_log_processor_info_t * (Ptr to processor device error record - * section body). - * prfunc (fn ptr of print function to be used - * for output). - * Outputs: None - */ -void -ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi, - prfunc_t prfunc) -{ -#ifdef MCA_PRT_XTRA_DATA - size_t d_len = slpi->header.len - sizeof(sal_log_section_hdr_t); -#endif - sal_processor_static_info_t *spsi; - int i; - sal_log_mod_error_info_t *p_data; + /* Setup the MCA rendezvous interrupt vector */ + register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); - prfunc("+Processor Device Error Info Section\n"); + /* Setup the MCA wakeup interrupt vector */ + register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL +#ifdef CONFIG_ACPI + /* Setup the CPE interrupt vector */ { - char *p_data = (char *)&slpi->valid; + irq_desc_t *desc; + unsigned int irq; + int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); - prfunc("SAL_PROC_DEV_ERR SECTION DATA: Data buffer = %p, " - "Data size = %ld\n", (void *)p_data, d_len); - ia64_log_hexdump(p_data, d_len, prfunc); - prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n"); + if (cpev >= 0) { + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == cpev) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_iosapic_level; + setup_irq(irq, &mca_cpe_irqaction); + } + ia64_mca_register_cpev(cpev); + } } -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if (slpi->valid.proc_error_map) - prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map); - - if (slpi->valid.proc_state_param) - prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter); - - if (slpi->valid.proc_cr_lid) - prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid); +#endif - /* - * Note: March 2001 SAL spec states that if the number of elements in any - * of the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is - * absent. Also, current implementations only allocate space for number of - * elements used. So we walk the data pointer from here on. + /* Initialize the areas set aside by the OS to buffer the + * platform/processor error states for MCA/INIT/CMC + * handling. */ - p_data = &slpi->info[0]; - - /* Print the cache check information if any*/ - for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++) - ia64_log_cache_check_info_print(i, p_data, prfunc); - - /* Print the tlb check information if any*/ - for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++) - ia64_log_tlb_check_info_print(i, p_data, prfunc); - - /* Print the bus check information if any*/ - for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++) - ia64_log_bus_check_info_print(i, p_data, prfunc); - - /* Print the reg file check information if any*/ - for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++) - ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), - prfunc); /* Just hex dump for now */ - - /* Print the ms check information if any*/ - for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++) - ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), - prfunc); /* Just hex dump for now */ - - /* Print CPUID registers if any*/ - if (slpi->valid.cpuid_info) { - u64 *p = (u64 *)p_data; - - prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); - p_data++; - } + ia64_log_init(SAL_INFO_TYPE_MCA); + ia64_log_init(SAL_INFO_TYPE_INIT); + ia64_log_init(SAL_INFO_TYPE_CMC); + ia64_log_init(SAL_INFO_TYPE_CPE); - /* Print processor static info if any */ - if (slpi->valid.psi_static_struct) { - spsi = (sal_processor_static_info_t *)p_data; - - /* Print branch register contents if valid */ - if (spsi->valid.br) - ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br", - prfunc); - - /* Print control register contents if valid */ - if (spsi->valid.cr) - ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr", - prfunc); - - /* Print application register contents if valid */ - if (spsi->valid.ar) - ia64_log_processor_regs_print(spsi->ar, 128, "Application", - "ar", prfunc); - - /* Print region register contents if valid */ - if (spsi->valid.rr) - ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr", - prfunc); - - /* Print floating-point register contents if valid */ - if (spsi->valid.fr) - ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr", - prfunc); - } + printk(KERN_INFO "MCA related initialization done\n"); } /* - * ia64_log_processor_info_print + * ia64_mca_late_init * - * Display the processor-specific information logged by PAL as a part - * of MCA or INIT or CMC. + * Opportunity to setup things that require initialization later + * than ia64_mca_init. Setup a timer to poll for CPEs if the + * platform doesn't support an interrupt driven mechanism. * - * Inputs : lh (Pointer of the sal log header which specifies the - * format of SAL state info as specified by the SAL spec). - * prfunc (fn ptr of print function to be used for output). - * Outputs : None + * Inputs : None + * Outputs : Status */ -void -ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc) +static int __init +ia64_mca_late_init(void) { - sal_log_section_hdr_t *slsh; - int n_sects; - u32 ercd_pos; - - if (!lh) - return; - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_record_header(lh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { - IA64_MCA_DEBUG("ia64_mca_log_print: " - "truncated SAL CMC error record. len = %d\n", - lh->len); - return; - } - - /* Print record header info */ - ia64_log_rec_header_print(lh, prfunc); - - for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { - /* point to next section header */ - slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_section_header(slsh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) { - IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); - continue; - } - - /* - * Now process processor device error record section - */ - ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, printk); - } - - IA64_MCA_DEBUG("ia64_mca_log_print: " - "found %d sections in SAL CMC error record. len = %d\n", - n_sects, lh->len); - if (!n_sects) { - prfunc("No Processor Device Error Info Section found\n"); - return; - } -} - -/* - * ia64_log_platform_info_print - * - * Format and Log the SAL Platform Error Record. - * - * Inputs : lh (Pointer to the sal error record header with format - * specified by the SAL spec). - * prfunc (fn ptr of log output function to use) - * Outputs : platform error status - */ -int -ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) -{ - sal_log_section_hdr_t *slsh; - int n_sects; - u32 ercd_pos; - int platform_err = 0; - - if (!lh) - return platform_err; - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_record_header(lh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { - IA64_MCA_DEBUG("ia64_mca_log_print: " - "truncated SAL error record. len = %d\n", - lh->len); - return platform_err; - } - - /* Print record header info */ - ia64_log_rec_header_print(lh, prfunc); - - for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { - /* point to next section header */ - slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_section_header(slsh, prfunc); - - if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) { - size_t d_len = slsh->len - sizeof(sal_log_section_hdr_t); - char *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid; - - prfunc("Start of Platform Err Data Section: Data buffer = %p, " - "Data size = %ld\n", (void *)p_data, d_len); - ia64_log_hexdump(p_data, d_len, prfunc); - prfunc("End of Platform Err Data Section\n"); - } -#endif // MCA_PRT_XTRA_DATA for test only @FVL + init_timer(&cmc_poll_timer); + cmc_poll_timer.function = ia64_mca_cmc_poll; - /* - * Now process CPE error record section - */ - if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) { - ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Memory Device Error Info Section\n"); - ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform SEL Device Error Info Section\n"); - ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform PCI Bus Error Info Section\n"); - ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform SMBIOS Device Error Info Section\n"); - ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform PCI Component Error Info Section\n"); - ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Specific Error Info Section\n"); - ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *) - slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Host Controller Error Info Section\n"); - ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Bus Error Info Section\n"); - ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh, - prfunc); - } else { - IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); - continue; - } - } + /* Reset to the correct state */ + cmc_polling_enabled = 0; - IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n", - n_sects, lh->len); - if (!n_sects) { - prfunc("No Platform Error Info Sections found\n"); - return platform_err; - } - return platform_err; -} + init_timer(&cpe_poll_timer); + cpe_poll_timer.function = ia64_mca_cpe_poll; -/* - * ia64_log_print - * - * Displays the contents of the OS error log information - * - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * prfunc (fn ptr of log output function to use) - * Outputs : platform error status - */ -int -ia64_log_print(int sal_info_type, prfunc_t prfunc) -{ - int platform_err = 0; - - switch(sal_info_type) { - case SAL_INFO_TYPE_MCA: - prfunc("+CPU %d: SAL log contains MCA error record\n", smp_processor_id()); - ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - break; - case SAL_INFO_TYPE_INIT: - prfunc("+CPU %d: SAL log contains INIT error record\n", smp_processor_id()); - ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - break; - case SAL_INFO_TYPE_CMC: - prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n"); - ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - prfunc("+END HARDWARE ERROR STATE AT CMC\n"); - break; - case SAL_INFO_TYPE_CPE: - prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n"); - ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - prfunc("+END HARDWARE ERROR STATE AT CPE\n"); - break; - default: - prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n"); - break; +#ifdef CONFIG_ACPI + /* If platform doesn't support CPEI, get the timer going. */ + if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) { + register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); + ia64_mca_cpe_poll(0UL); } - return platform_err; -} +#endif -static int __init -ia64_mca_disable_cpe_polling(char *str) -{ - cpe_poll_enabled = 0; - return 1; + return 0; } -__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); +module_init(ia64_mca_late_init); diff -urN linux-2.4.25/arch/ia64/kernel/pci.c linux-2.4.26/arch/ia64/kernel/pci.c --- linux-2.4.25/arch/ia64/kernel/pci.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/pci.c 2004-04-14 06:05:26.000000000 -0700 @@ -386,10 +386,6 @@ void __init pcibios_init (void) { -#ifdef CONFIG_IA64_MCA - ia64_mca_check_errors(); /* For post-failure MCA error logging */ -#endif - pcibios_config_init(); platform_pci_fixup(0); /* phase 0 fixups (before buses scanned) */ diff -urN linux-2.4.25/arch/ia64/kernel/ptrace.c linux-2.4.26/arch/ia64/kernel/ptrace.c --- linux-2.4.25/arch/ia64/kernel/ptrace.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/ptrace.c 2004-04-14 06:05:26.000000000 -0700 @@ -63,12 +63,25 @@ ({ \ unsigned long bit = ia64_unat_pos(&pt->r##first); \ unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ - (ia64_rotl(unat, first) >> bit) & mask; \ + unsigned long dist; \ + if (bit < first) \ + dist = 64 + bit - first; \ + else \ + dist = bit - first; \ + ia64_rotr(unat, dist) & mask; \ }) unsigned long val; - val = GET_BITS( 1, 3, scratch_unat); - val |= GET_BITS(12, 15, scratch_unat); + /* + * Registers that are stored consecutively in struct pt_regs can be handled in + * parallel. If the register order in struct_pt_regs changes, this code MUST be + * updated. + */ + val = GET_BITS( 1, 1, scratch_unat); + val |= GET_BITS( 2, 3, scratch_unat); + val |= GET_BITS(12, 13, scratch_unat); + val |= GET_BITS(14, 14, scratch_unat); + val |= GET_BITS(15, 15, scratch_unat); val |= GET_BITS( 8, 11, scratch_unat); val |= GET_BITS(16, 31, scratch_unat); return val; @@ -84,16 +97,29 @@ unsigned long ia64_put_scratch_nat_bits (struct pt_regs *pt, unsigned long nat) { +# define PUT_BITS(first, last, nat) \ + ({ \ + unsigned long bit = ia64_unat_pos(&pt->r##first); \ + unsigned long mask = ((1UL << (last - first + 1)) - 1) << first; \ + long dist; \ + if (bit < first) \ + dist = 64 + bit - first; \ + else \ + dist = bit - first; \ + ia64_rotl(nat & mask, dist); \ + }) unsigned long scratch_unat; -# define PUT_BITS(first, last, nat) \ - ({ \ - unsigned long bit = ia64_unat_pos(&pt->r##first); \ - unsigned long mask = ((1UL << (last - first + 1)) - 1) << bit; \ - (ia64_rotr(nat, first) << bit) & mask; \ - }) - scratch_unat = PUT_BITS( 1, 3, nat); - scratch_unat |= PUT_BITS(12, 15, nat); + /* + * Registers that are stored consecutively in struct pt_regs can be handled in + * parallel. If the register order in struct_pt_regs changes, this code MUST be + * updated. + */ + scratch_unat = PUT_BITS( 1, 1, nat); + scratch_unat |= PUT_BITS( 2, 3, nat); + scratch_unat |= PUT_BITS(12, 13, nat); + scratch_unat |= PUT_BITS(14, 14, nat); + scratch_unat |= PUT_BITS(15, 15, nat); scratch_unat |= PUT_BITS( 8, 11, nat); scratch_unat |= PUT_BITS(16, 31, nat); diff -urN linux-2.4.25/arch/ia64/kernel/salinfo.c linux-2.4.26/arch/ia64/kernel/salinfo.c --- linux-2.4.25/arch/ia64/kernel/salinfo.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/salinfo.c 2004-04-14 06:05:26.000000000 -0700 @@ -16,6 +16,13 @@ * Cache the record across multi-block reads from user space. * Support > 64 cpus. * Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module. + * + * Jan 28 2004 kaos@sgi.com + * Periodically check for outstanding MCA or INIT records. + * + * Feb 21 2004 kaos@sgi.com + * Copy record contents rather than relying on the mca.c buffers, to cope with + * interrupts arriving in mca.c faster than salinfo.c can process them. */ #include @@ -23,6 +30,7 @@ #include #include #include +#include #include #include @@ -83,6 +91,7 @@ u64 size; u64 id; int cpu; + int kmalloced :1; /* buffer was kmalloc'ed */ }; /* State transitions. Actions are :- @@ -178,6 +187,8 @@ static void shift1_data_saved (struct salinfo_data *data, int shift) { + if (data->data_saved[shift].kmalloced) + kfree(data->data_saved[shift].buffer); memcpy(data->data_saved+shift, data->data_saved+shift+1, (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0])); memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0, @@ -187,6 +198,8 @@ /* This routine is invoked in interrupt context. Note: mca.c enables * interrupts before calling this code for CMC/CPE. MCA and INIT events are * not irq safe, do not call any routines that use spinlocks, they may deadlock. + * MCA and INIT records are recorded, a timer event will look for any + * outstanding events and wake up the user space code. * * The buffer passed from mca.c points to the output from ia64_log_get. This is * a persistent buffer but its contents can change between the interrupt and @@ -194,12 +207,12 @@ * changes. */ void -salinfo_log_wakeup(int type, u8 *buffer, u64 size) +salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) { struct salinfo_data *data = salinfo_data + type; struct salinfo_data_saved *data_saved; unsigned long flags = 0; - int i, irqsafe = type != SAL_INFO_TYPE_MCA && type != SAL_INFO_TYPE_INIT; + int i; int saved_size = ARRAY_SIZE(data->data_saved); BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); @@ -221,7 +234,13 @@ data_saved->cpu = smp_processor_id(); data_saved->id = ((sal_log_record_header_t *)buffer)->id; data_saved->size = size; - data_saved->buffer = buffer; + if (irqsafe && (data_saved->buffer = kmalloc(size, GFP_ATOMIC))) { + memcpy(data_saved->buffer, buffer, size); + data_saved->kmalloced = 1; + } else { + data_saved->buffer = buffer; + data_saved->kmalloced = 0; + } } if (irqsafe) spin_unlock_irqrestore(&data_saved_lock, flags); @@ -232,6 +251,35 @@ } } +/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */ +#define SALINFO_TIMER_DELAY (5*60*HZ) +static struct timer_list salinfo_timer; + +static void +salinfo_timeout_check(struct salinfo_data *data) +{ + int i; + if (!data->open) + return; + for (i = 0; i < NR_CPUS; ++i) { + if (test_bit(i, &data->cpu_event)) { + /* double up() is not a problem, user space will see no + * records for the additional "events". + */ + up(&data->sem); + } + } +} + +static void +salinfo_timeout (unsigned long arg) +{ + salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA); + salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT); + salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; + add_timer(&salinfo_timer); +} + static int salinfo_event_open(struct inode *inode, struct file *file) { @@ -571,6 +619,11 @@ *sdir++ = salinfo_dir; + init_timer(&salinfo_timer); + salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; + salinfo_timer.function = &salinfo_timeout; + add_timer(&salinfo_timer); + return 0; } diff -urN linux-2.4.25/arch/ia64/kernel/signal.c linux-2.4.26/arch/ia64/kernel/signal.c --- linux-2.4.25/arch/ia64/kernel/signal.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/signal.c 2004-04-14 06:05:26.000000000 -0700 @@ -349,12 +349,6 @@ __copy_to_user(&sc->sc_fr[32], current->thread.fph, 96*16); } - /* - * Note: sw->ar_unat is UNDEFINED unless the process is being - * PTRACED. However, this is OK because the NaT bits of the - * preserved registers (r4-r7) are never being looked at by - * the signal handler (registers r4-r7 are used instead). - */ nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); err = __put_user(flags, &sc->sc_flags); diff -urN linux-2.4.25/arch/ia64/kernel/smpboot.c linux-2.4.26/arch/ia64/kernel/smpboot.c --- linux-2.4.25/arch/ia64/kernel/smpboot.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/smpboot.c 2004-04-14 06:05:26.000000000 -0700 @@ -349,7 +349,6 @@ #ifdef CONFIG_IA64_MCA ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */ - ia64_mca_check_errors(); /* For post-failure MCA error logging */ #endif #ifdef CONFIG_PERFMON diff -urN linux-2.4.25/arch/ia64/kernel/unwind.c linux-2.4.26/arch/ia64/kernel/unwind.c --- linux-2.4.25/arch/ia64/kernel/unwind.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ia64/kernel/unwind.c 2004-04-14 06:05:26.000000000 -0700 @@ -1,9 +1,8 @@ /* - * Copyright (C) 2003 Fenghua Yu - * - Change pt_regs_off() to make it less dependant on pt_regs structure. - * * Copyright (C) 1999-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 2003 Fenghua Yu + * - Change pt_regs_off() to make it less dependant on pt_regs structure. */ /* * This file implements call frame unwind support for the Linux @@ -27,7 +26,9 @@ * o if both the unw.lock spinlock and a script's read-write lock must be * acquired, then the read-write lock must be acquired first. */ +#include #include +#include #include #include #include @@ -58,15 +59,9 @@ #ifdef UNW_DEBUG static unsigned int unw_debug_level = UNW_DEBUG; -# ifdef CONFIG_KDB -# include -# define UNW_DEBUG_ON(n) (unw_debug_level >= n && !KDB_IS_RUNNING()) -# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) kdb_printf(__VA_ARGS__) -# else /* !CONFIG_KDB */ -# define UNW_DEBUG_ON(n) unw_debug_level >= n - /* Do not code a printk level, not all debug lines end in newline */ -# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) -# endif /* CONFIG_KDB */ +# define UNW_DEBUG_ON(n) unw_debug_level >= n + /* Do not code a printk level, not all debug lines end in newline */ +# define UNW_DPRINT(n, ...) if (UNW_DEBUG_ON(n)) printk(__VA_ARGS__) # define inline #else /* !UNW_DEBUG */ # define UNW_DEBUG_ON(n) 0 @@ -79,7 +74,7 @@ # define STAT(x...) #endif -#define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) +#define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) @@ -87,8 +82,6 @@ typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; -#define struct_offset(str,fld) ((char *)&((str *)NULL)->fld - (char *) 0) - static struct { spinlock_t lock; /* spinlock for unwind data */ @@ -107,6 +100,8 @@ /* index into unw_frame_info for preserved register i */ unsigned short preg_index[UNW_NUM_REGS]; + short pt_regs_offsets[32]; + /* unwind table for the kernel: */ struct unw_table kernel_table; @@ -156,47 +151,78 @@ UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR }, .preg_index = { - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ - struct_offset(struct unw_frame_info, bsp_loc)/8, - struct_offset(struct unw_frame_info, bspstore_loc)/8, - struct_offset(struct unw_frame_info, pfs_loc)/8, - struct_offset(struct unw_frame_info, rnat_loc)/8, - struct_offset(struct unw_frame_info, psp)/8, - struct_offset(struct unw_frame_info, rp_loc)/8, - struct_offset(struct unw_frame_info, r4)/8, - struct_offset(struct unw_frame_info, r5)/8, - struct_offset(struct unw_frame_info, r6)/8, - struct_offset(struct unw_frame_info, r7)/8, - struct_offset(struct unw_frame_info, unat_loc)/8, - struct_offset(struct unw_frame_info, pr_loc)/8, - struct_offset(struct unw_frame_info, lc_loc)/8, - struct_offset(struct unw_frame_info, fpsr_loc)/8, - struct_offset(struct unw_frame_info, b1_loc)/8, - struct_offset(struct unw_frame_info, b2_loc)/8, - struct_offset(struct unw_frame_info, b3_loc)/8, - struct_offset(struct unw_frame_info, b4_loc)/8, - struct_offset(struct unw_frame_info, b5_loc)/8, - struct_offset(struct unw_frame_info, f2_loc)/8, - struct_offset(struct unw_frame_info, f3_loc)/8, - struct_offset(struct unw_frame_info, f4_loc)/8, - struct_offset(struct unw_frame_info, f5_loc)/8, - struct_offset(struct unw_frame_info, fr_loc[16 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[17 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[18 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[19 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[20 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[21 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[22 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[23 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[24 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[25 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[26 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[27 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[28 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[29 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8, + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ + offsetof(struct unw_frame_info, bsp_loc)/8, + offsetof(struct unw_frame_info, bspstore_loc)/8, + offsetof(struct unw_frame_info, pfs_loc)/8, + offsetof(struct unw_frame_info, rnat_loc)/8, + offsetof(struct unw_frame_info, psp)/8, + offsetof(struct unw_frame_info, rp_loc)/8, + offsetof(struct unw_frame_info, r4)/8, + offsetof(struct unw_frame_info, r5)/8, + offsetof(struct unw_frame_info, r6)/8, + offsetof(struct unw_frame_info, r7)/8, + offsetof(struct unw_frame_info, unat_loc)/8, + offsetof(struct unw_frame_info, pr_loc)/8, + offsetof(struct unw_frame_info, lc_loc)/8, + offsetof(struct unw_frame_info, fpsr_loc)/8, + offsetof(struct unw_frame_info, b1_loc)/8, + offsetof(struct unw_frame_info, b2_loc)/8, + offsetof(struct unw_frame_info, b3_loc)/8, + offsetof(struct unw_frame_info, b4_loc)/8, + offsetof(struct unw_frame_info, b5_loc)/8, + offsetof(struct unw_frame_info, f2_loc)/8, + offsetof(struct unw_frame_info, f3_loc)/8, + offsetof(struct unw_frame_info, f4_loc)/8, + offsetof(struct unw_frame_info, f5_loc)/8, + offsetof(struct unw_frame_info, fr_loc[16 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[17 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[18 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[19 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[20 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[21 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[22 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[23 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[24 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[25 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[26 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[27 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[28 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[29 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[30 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[31 - 16])/8, + }, + .pt_regs_offsets = { + [0] = -1, + offsetof(struct pt_regs, r1), + offsetof(struct pt_regs, r2), + offsetof(struct pt_regs, r3), + [4] = -1, [5] = -1, [6] = -1, [7] = -1, + offsetof(struct pt_regs, r8), + offsetof(struct pt_regs, r9), + offsetof(struct pt_regs, r10), + offsetof(struct pt_regs, r11), + offsetof(struct pt_regs, r12), + offsetof(struct pt_regs, r13), + offsetof(struct pt_regs, r14), + offsetof(struct pt_regs, r15), + offsetof(struct pt_regs, r16), + offsetof(struct pt_regs, r17), + offsetof(struct pt_regs, r18), + offsetof(struct pt_regs, r19), + offsetof(struct pt_regs, r20), + offsetof(struct pt_regs, r21), + offsetof(struct pt_regs, r22), + offsetof(struct pt_regs, r23), + offsetof(struct pt_regs, r24), + offsetof(struct pt_regs, r25), + offsetof(struct pt_regs, r26), + offsetof(struct pt_regs, r27), + offsetof(struct pt_regs, r28), + offsetof(struct pt_regs, r29), + offsetof(struct pt_regs, r30), + offsetof(struct pt_regs, r31), }, .hash = { [0 ... UNW_HASH_SIZE - 1] = -1 }, #ifdef UNW_DEBUG @@ -212,11 +238,6 @@ #endif }; -#define OFF_CASE(reg, reg_num) \ - case reg: \ - off=struct_offset(struct pt_regs, reg_num); \ - break; - /* Unwind accessors. */ /* @@ -225,43 +246,16 @@ static inline unsigned long pt_regs_off (unsigned long reg) { - unsigned long off =0; + short off = -1; - switch (reg) - { - OFF_CASE(1,r1) - OFF_CASE(2,r2) - OFF_CASE(3,r3) - OFF_CASE(8,r8) - OFF_CASE(9,r9) - OFF_CASE(10,r10) - OFF_CASE(11,r11) - OFF_CASE(12,r12) - OFF_CASE(13,r13) - OFF_CASE(14,r14) - OFF_CASE(15,r15) - OFF_CASE(16,r16) - OFF_CASE(17,r17) - OFF_CASE(18,r18) - OFF_CASE(19,r19) - OFF_CASE(20,r20) - OFF_CASE(21,r21) - OFF_CASE(22,r22) - OFF_CASE(23,r23) - OFF_CASE(24,r24) - OFF_CASE(25,r25) - OFF_CASE(26,r26) - OFF_CASE(27,r27) - OFF_CASE(28,r28) - OFF_CASE(29,r29) - OFF_CASE(30,r30) - OFF_CASE(31,r31) - default: - UNW_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg); - break; - } + if (reg < ARRAY_SIZE(unw.pt_regs_offsets)) + off = unw.pt_regs_offsets[reg]; - return off; + if (off < 0) { + UNW_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg); + off = 0; + } + return (unsigned long) off; } static inline struct pt_regs * @@ -398,6 +392,7 @@ } return 0; } +EXPORT_SYMBOL(unw_access_gr); int unw_access_br (struct unw_frame_info *info, int regnum, unsigned long *val, int write) @@ -429,6 +424,7 @@ *val = *addr; return 0; } +EXPORT_SYMBOL(unw_access_br); int unw_access_fr (struct unw_frame_info *info, int regnum, struct ia64_fpreg *val, int write) @@ -473,6 +469,7 @@ *val = *addr; return 0; } +EXPORT_SYMBOL(unw_access_fr); int unw_access_ar (struct unw_frame_info *info, int regnum, unsigned long *val, int write) @@ -565,6 +562,7 @@ *val = *addr; return 0; } +EXPORT_SYMBOL(unw_access_ar); int unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) @@ -581,6 +579,7 @@ *val = *addr; return 0; } +EXPORT_SYMBOL(unw_access_pr); /* Routines to manipulate the state stack. */ @@ -826,7 +825,7 @@ static inline void desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) { - if (abi == 0 && context == 'i') { + if (abi == 3 && context == 'i') { sr->flags |= UNW_FLAG_INTERRUPT_FRAME; UNW_DPRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__); } @@ -1177,9 +1176,10 @@ static inline unw_hash_index_t hash (unsigned long ip) { -# define magic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ +# define hashmagic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */ - return (ip >> 4)*magic >> (64 - UNW_LOG_HASH_SIZE); + return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE); +#undef hashmagic } static inline long @@ -1258,13 +1258,18 @@ spin_unlock(&unw.lock); /* - * XXX We'll deadlock here if we interrupt a thread that is - * holding a read lock on script->lock. A try_write_lock() - * might be mighty handy here... Alternatively, we could - * disable interrupts whenever we hold a read-lock, but that - * seems silly. + * We'd deadlock here if we interrupted a thread that is holding a read lock on + * script->lock. Thus, if the write_trylock() fails, we simply bail out. The + * alternative would be to disable interrupts whenever we hold a read-lock, but + * that seems silly. */ - write_lock(&script->lock); + /* Kludge: 2.4 has down_write_trylock on semaphores but not write_trylock on + * spinlocks, even though they are both in 2.6 and are identical. Pretend + * that script lock is a rw_semaphore so we can use the only 2.4 code that + * avoids a deadlock. KAO. + */ + if (!down_write_trylock((struct rw_semaphore *)(&script->lock))) + return NULL; spin_lock(&unw.lock); { @@ -1415,13 +1420,13 @@ case UNW_WHERE_FR: if (rval <= 5) - val = unw.preg_index[UNW_REG_F2 + (rval - 1)]; + val = unw.preg_index[UNW_REG_F2 + (rval - 2)]; else if (rval >= 16 && rval <= 31) val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; else { opc = UNW_INSN_MOVE_SCRATCH; if (rval <= 11) - val = struct_offset(struct pt_regs, f6) + 16*(rval - 6); + val = offsetof(struct pt_regs, f6) + 16*(rval - 6); else UNW_DPRINT(0, "unwind.%s: kernel may not touch f%lu\n", __FUNCTION__, rval); @@ -1434,11 +1439,11 @@ else { opc = UNW_INSN_MOVE_SCRATCH; if (rval == 0) - val = struct_offset(struct pt_regs, b0); + val = offsetof(struct pt_regs, b0); else if (rval == 6) - val = struct_offset(struct pt_regs, b6); + val = offsetof(struct pt_regs, b6); else - val = struct_offset(struct pt_regs, b7); + val = offsetof(struct pt_regs, b7); } break; @@ -1638,7 +1643,7 @@ && sr.curr.reg[UNW_REG_PSP].val != 0) { /* new psp is sp plus frame size */ insn.opc = UNW_INSN_ADD; - insn.dst = struct_offset(struct unw_frame_info, psp)/8; + insn.dst = offsetof(struct unw_frame_info, psp)/8; insn.val = sr.curr.reg[UNW_REG_PSP].val; /* frame size */ script_emit(script, insn); } @@ -1772,13 +1777,13 @@ lazy_init: off = unw.sw_off[val]; s[val] = (unsigned long) state->sw + off; - if (off >= struct_offset(struct switch_stack, r4) && off <= struct_offset(struct switch_stack, r7)) + if (off >= offsetof(struct switch_stack, r4) && off <= offsetof(struct switch_stack, r7)) /* * We're initializing a general register: init NaT info, too. Note that * the offset is a multiple of 8 which gives us the 3 bits needed for * the type field. */ - s[val+1] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; + s[val+1] = (offsetof(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; goto redo; } @@ -1868,7 +1873,7 @@ if ((pr & (1UL << pNonSys)) != 0) num_regs = *info->cfm_loc & 0x7f; /* size of frame */ info->pfs_loc = - (unsigned long *) (info->pt + struct_offset(struct pt_regs, ar_pfs)); + (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); UNW_DPRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt); } else num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */ @@ -1906,6 +1911,7 @@ STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return retval; } +EXPORT_SYMBOL(unw_unwind); int unw_unwind_to_user (struct unw_frame_info *info) @@ -1930,6 +1936,7 @@ UNW_DPRINT(0, "unwind.%s: failed to unwind to user-level (ip=0x%lx)\n", __FUNCTION__, ip); return -1; } +EXPORT_SYMBOL(unw_unwind_to_user); static void init_frame_info (struct unw_frame_info *info, struct task_struct *t, @@ -1987,6 +1994,8 @@ init_frame_info(info, t, sw, pt->r12); info->cfm_loc = &pt->cr_ifs; + info->unat_loc = &pt->ar_unat; + info->pfs_loc = &pt->ar_pfs; sof = *info->cfm_loc & 0x7f; info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof); info->ip = pt->cr_iip + ia64_psr(pt)->ri; @@ -2025,6 +2034,7 @@ UNW_DPRINT(1, "unwind.%s\n", __FUNCTION__); unw_init_frame_info(info, t, sw); } +EXPORT_SYMBOL(unw_init_from_blocked_task); static void init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base, diff -urN linux-2.4.25/arch/ia64/kernel/unwind_i.h linux-2.4.26/arch/ia64/kernel/unwind_i.h --- linux-2.4.25/arch/ia64/kernel/unwind_i.h 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.26/arch/ia64/kernel/unwind_i.h 2004-04-14 06:05:26.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2002 Hewlett-Packard Co + * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co * David Mosberger-Tang * * Kernel unwind support. @@ -45,12 +45,6 @@ /* personality routine and language-specific data follow behind descriptors */ }; -struct unw_table_entry { - u64 start_offset; - u64 end_offset; - u64 info_offset; -}; - struct unw_table { struct unw_table *next; /* must be first member! */ const char *name; @@ -148,7 +142,7 @@ }; /* - * Preserved general static registers (r2-r5) give rise to two script + * Preserved general static registers (r4-r7) give rise to two script * instructions; everything else yields at most one instruction; at * the end of the script, the psp gets popped, accounting for one more * instruction. diff -urN linux-2.4.25/arch/ia64/sn/kernel/mca.c linux-2.4.26/arch/ia64/sn/kernel/mca.c --- linux-2.4.25/arch/ia64/sn/kernel/mca.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.26/arch/ia64/sn/kernel/mca.c 2004-04-14 06:05:26.000000000 -0700 @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -53,6 +55,41 @@ struct timer_list sn_cpei_timer; void sn_init_cpei_timer(void); +/* Printing oemdata from mca uses data that is not passed through SAL, it is + * global. Only one user at a time. + */ +static DECLARE_MUTEX(sn_oemdata_mutex); +static u8 **sn_oemdata; +static u64 *sn_oemdata_size, sn_oemdata_bufsize; + +/* Called as the "printk" routine via sn_platform_plat_specific_err_print, + * ia64_sn_plat_specific_err_print through SAL to print_hook. It only handles + * a print of '"%s", buf'. buf is appended to sn_oemdata, resizing as required. + */ +static int +sn_oemdata_print(const char *fmt, ...) +{ + va_list args; + char *buf; + int len; + va_start(args, fmt); + buf = va_arg(args, char *); + va_end(args); + len = strlen(buf); + while (*sn_oemdata_size + len + 1 > sn_oemdata_bufsize) { + u8 *newbuf = vmalloc(sn_oemdata_bufsize += 1000); + if (!newbuf) { + printk(KERN_ERR "%s: unable to extend sn_oemdata\n", __FUNCTION__); + return 0; + } + memcpy(newbuf, *sn_oemdata, *sn_oemdata_size); + vfree(*sn_oemdata); + *sn_oemdata = newbuf; + } + memcpy(*sn_oemdata + *sn_oemdata_size, buf, len + 1); + *sn_oemdata_size += len; + return len; +} /* * print_hook @@ -86,25 +123,11 @@ newline = (p != 0); va_end(args); - printk("%s", buf); + sn_oemdata_print("%s", buf); /* args must be '"%s", buf' */ return len; } - -/* - * ia64_sn2_platform_plat_specific_err_print - * - * Called by the MCA handler to log platform-specific errors. - */ -void -ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) -{ - ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); -} - - - static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) { @@ -132,3 +155,42 @@ sn_cpei_timer.function = sn_cpei_timer_handler; add_timer(&sn_cpei_timer); } + +static int +sn_platform_plat_specific_err_print(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size) +{ + sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header; + if (!psei->valid.oem_data) + return 0; + down(&sn_oemdata_mutex); + sn_oemdata = oemdata; + sn_oemdata_size = oemdata_size; + ia64_sn_plat_specific_err_print(print_hook, (char *)psei); + up(&sn_oemdata_mutex); + return 0; +} + +/* Callback when userspace salinfo wants to decode oem data via the platform + * kernel and/or prom. + */ +int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size) +{ + efi_guid_t guid = *(efi_guid_t *)sect_header; + *oemdata_size = 0; + sn_oemdata_bufsize = 0; + vfree(*oemdata); + *oemdata = NULL; + if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) + return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size); + return 0; +} + +static int __init sn_salinfo_init(void) +{ + salinfo_platform_oemdata = &sn_salinfo_platform_oemdata; + return 0; +} + +module_init(sn_salinfo_init) + + diff -urN linux-2.4.25/arch/ia64/tools/Makefile linux-2.4.26/arch/ia64/tools/Makefile --- linux-2.4.25/arch/ia64/tools/Makefile 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ia64/tools/Makefile 2004-04-14 06:05:26.000000000 -0700 @@ -5,6 +5,7 @@ all: mrproper: clean + rm -f $(TARGET) clean: rm -f print_offsets.s print_offsets offsets.h diff -urN linux-2.4.25/arch/m68k/mac/baboon.c linux-2.4.26/arch/m68k/mac/baboon.c --- linux-2.4.25/arch/m68k/mac/baboon.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/m68k/mac/baboon.c 2004-04-14 06:05:26.000000000 -0700 @@ -19,8 +19,8 @@ #include #include -/* #define DEBUG_BABOON /**/ -/* #define DEBUG_IRQS /**/ +/* #define DEBUG_BABOON */ +/* #define DEBUG_IRQS */ int baboon_present,baboon_active; volatile struct baboon *baboon; diff -urN linux-2.4.25/arch/m68k/mac/config.c linux-2.4.26/arch/m68k/mac/config.c --- linux-2.4.25/arch/m68k/mac/config.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.26/arch/m68k/mac/config.c 2004-04-14 06:05:26.000000000 -0700 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include diff -urN linux-2.4.25/arch/ppc/8260_io/Config.in linux-2.4.26/arch/ppc/8260_io/Config.in --- linux-2.4.25/arch/ppc/8260_io/Config.in 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/8260_io/Config.in 1969-12-31 16:00:00.000000000 -0800 @@ -1,26 +0,0 @@ -# -# MPC8260 Communication options -# -mainmenu_option next_comment -comment 'MPC8260 CPM Options' -bool 'Enable SCC Console' CONFIG_SCC_CONSOLE -if [ "$CONFIG_NET_ETHERNET" = "y" ]; then - bool 'CPM SCC Ethernet' CONFIG_SCC_ENET - if [ "$CONFIG_SCC_ENET" = "y" ]; then - bool 'Ethernet on SCC1' CONFIG_SCC1_ENET - if [ "$CONFIG_SCC1_ENET" != "y" ]; then - bool 'Ethernet on SCC2' CONFIG_SCC2_ENET - fi - fi -# -# CONFIG_FEC_ENET is only used to get netdevices to call our init -# function. Any combination of FCC1,2,3 are supported. -# - bool 'FCC Ethernet' CONFIG_FEC_ENET - if [ "$CONFIG_FEC_ENET" = "y" ]; then - bool 'Ethernet on FCC1' CONFIG_FCC1_ENET - bool 'Ethernet on FCC2' CONFIG_FCC2_ENET - bool 'Ethernet on FCC3' CONFIG_FCC3_ENET - fi -fi -endmenu diff -urN linux-2.4.25/arch/ppc/8260_io/Makefile linux-2.4.26/arch/ppc/8260_io/Makefile --- linux-2.4.25/arch/ppc/8260_io/Makefile 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/8260_io/Makefile 1969-12-31 16:00:00.000000000 -0800 @@ -1,17 +0,0 @@ -# -# Makefile for the linux MPC8xx ppc-specific parts of comm processor -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... - -O_TARGET := 8260_io.o - -obj-y := commproc.o uart.o - -obj-$(CONFIG_FEC_ENET) += fcc_enet.o -obj-$(CONFIG_SCC_ENET) += enet.o - -include $(TOPDIR)/Rules.make diff -urN linux-2.4.25/arch/ppc/8260_io/commproc.c linux-2.4.26/arch/ppc/8260_io/commproc.c --- linux-2.4.25/arch/ppc/8260_io/commproc.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/8260_io/commproc.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,179 +0,0 @@ -/* - * General Purpose functions for the global management of the - * 8260 Communication Processor Module. - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) - * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) - * 2.3.99 Updates - * - * In addition to the individual control of the communication - * channels, there are a few functions that globally affect the - * communication processor. - * - * Buffer descriptors must be allocated from the dual ported memory - * space. The allocator for that is here. When the communication - * process is reset, we reclaim the memory available. There is - * currently no deallocator for this memory. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static uint dp_alloc_base; /* Starting offset in DP ram */ -static uint dp_alloc_top; /* Max offset + 1 */ -static uint host_buffer; /* One page of host buffer */ -static uint host_end; /* end + 1 */ -cpm8260_t *cpmp; /* Pointer to comm processor space */ - -/* We allocate this here because it is used almost exclusively for - * the communication processor devices. - */ -immap_t *immr; - -void -m8260_cpm_reset(void) -{ - volatile immap_t *imp; - volatile cpm8260_t *commproc; - uint vpgaddr; - - immr = imp = (volatile immap_t *)IMAP_ADDR; - commproc = &imp->im_cpm; - - /* Reclaim the DP memory for our use. - */ - dp_alloc_base = CPM_DATAONLY_BASE; - dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; - - /* Set the host page for allocation. - */ - host_buffer = - (uint) alloc_bootmem_pages(PAGE_SIZE * NUM_CPM_HOST_PAGES); - host_end = host_buffer + (PAGE_SIZE * NUM_CPM_HOST_PAGES); - - vpgaddr = host_buffer; - - /* Tell everyone where the comm processor resides. - */ - cpmp = (cpm8260_t *)commproc; -} - -/* Allocate some memory from the dual ported ram. - * To help protocols with object alignment restrictions, we do that - * if they ask. - */ -uint -m8260_cpm_dpalloc(uint size, uint align) -{ - uint retloc; - uint align_mask, off; - uint savebase; - - align_mask = align - 1; - savebase = dp_alloc_base; - - if ((off = (dp_alloc_base & align_mask)) != 0) - dp_alloc_base += (align - off); - - if ((dp_alloc_base + size) >= dp_alloc_top) { - dp_alloc_base = savebase; - return(CPM_DP_NOSPACE); - } - - retloc = dp_alloc_base; - dp_alloc_base += size; - - return(retloc); -} - -/* We also own one page of host buffer space for the allocation of - * UART "fifos" and the like. - */ -uint -m8260_cpm_hostalloc(uint size, uint align) -{ - uint retloc; - uint align_mask, off; - uint savebase; - - align_mask = align - 1; - savebase = host_buffer; - - if ((off = (host_buffer & align_mask)) != 0) - host_buffer += (align - off); - - if ((host_buffer + size) >= host_end) { - host_buffer = savebase; - return(0); - } - - retloc = host_buffer; - host_buffer += size; - - return(retloc); -} - -/* Set a baud rate generator. This needs lots of work. There are - * eight BRGs, which can be connected to the CPM channels or output - * as clocks. The BRGs are in two different block of internal - * memory mapped space. - * The baud rate clock is the system clock divided by something. - * It was set up long ago during the initial boot phase and is - * is given to us. - * Baud rate clocks are zero-based in the driver code (as that maps - * to port numbers). Documentation uses 1-based numbering. - */ -#define BRG_INT_CLK (((bd_t *)__res)->bi_brgfreq) -#define BRG_UART_CLK (BRG_INT_CLK/16) - -/* This function is used by UARTS, or anything else that uses a 16x - * oversampled clock. - */ -void -m8260_cpm_setbrg(uint brg, uint rate) -{ - volatile uint *bp; - - /* This is good enough to get SMCs running..... - */ - if (brg < 4) { - bp = (uint *)&immr->im_brgc1; - } - else { - bp = (uint *)&immr->im_brgc5; - brg -= 4; - } - bp += brg; - *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN; -} - -/* This function is used to set high speed synchronous baud rate - * clocks. - */ -void -m8260_cpm_fastbrg(uint brg, uint rate, int div16) -{ - volatile uint *bp; - - if (brg < 4) { - bp = (uint *)&immr->im_brgc1; - } - else { - bp = (uint *)&immr->im_brgc5; - brg -= 4; - } - bp += brg; - *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; - if (div16) - *bp |= CPM_BRG_DIV16; -} diff -urN linux-2.4.25/arch/ppc/8260_io/enet.c linux-2.4.26/arch/ppc/8260_io/enet.c --- linux-2.4.25/arch/ppc/8260_io/enet.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/arch/ppc/8260_io/enet.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,857 +0,0 @@ -/* - * Ethernet driver for Motorola MPC8260. - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) - * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com) - * 2.3.99 Updates - * - * I copied this from the 8xx CPM Ethernet driver, so follow the - * credits back through that. - * - * This version of the driver is somewhat selectable for the different - * processor/board combinations. It works for the boards I know about - * now, and should be easily modified to include others. Some of the - * configuration information is contained in and the - * remainder is here. - * - * Buffer descriptors are kept in the CPM dual port RAM, and the frame - * buffers are in the host memory. - * - * Right now, I am very watseful with the buffers. I allocate memory - * pages and then divide them into 2K frame buffers. This way I know I - * have buffers large enough to hold one frame within one buffer descriptor. - * Once I get this working, I will use 64 or 128 byte CPM buffers, which - * will be much more memory efficient and will easily handle lots of - * small packets. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* - * Theory of Operation - * - * The MPC8260 CPM performs the Ethernet processing on an SCC. It can use - * an aribtrary number of buffers on byte boundaries, but must have at - * least two receive buffers to prevent constant overrun conditions. - * - * The buffer descriptors are allocated from the CPM dual port memory - * with the data buffers allocated from host memory, just like all other - * serial communication protocols. The host memory buffers are allocated - * from the free page pool, and then divided into smaller receive and - * transmit buffers. The size of the buffers should be a power of two, - * since that nicely divides the page. This creates a ring buffer - * structure similar to the LANCE and other controllers. - * - * Like the LANCE driver: - * The driver runs as two independent, single-threaded flows of control. One - * is the send-packet routine, which enforces single-threaded use by the - * cep->tx_busy flag. The other thread is the interrupt handler, which is - * single threaded by the hardware and other software. - */ - -/* The transmitter timeout - */ -#define TX_TIMEOUT (2*HZ) - -/* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it is best - * to keep them that size. - * We don't need to allocate pages for the transmitter. We just use - * the skbuffer directly. - */ -#define CPM_ENET_RX_PAGES 4 -#define CPM_ENET_RX_FRSIZE 2048 -#define CPM_ENET_RX_FRPPG (PAGE_SIZE / CPM_ENET_RX_FRSIZE) -#define RX_RING_SIZE (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES) -#define TX_RING_SIZE 8 /* Must be power of two */ -#define TX_RING_MOD_MASK 7 /* for this to work */ - -/* The CPM stores dest/src/type, data, and checksum for receive packets. - */ -#define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1520 - -/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. - * The dirty_tx tracks the current buffer that is being sent by the - * controller. The cur_tx and dirty_tx are equal under both completely - * empty and completely full conditions. The empty/ready indicator in - * the buffer descriptor determines the actual condition. - */ -struct scc_enet_private { - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; - - /* CPM dual port RAM relative addresses. - */ - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ - cbd_t *dirty_tx; /* The ring entries to be free()ed. */ - scc_t *sccp; - struct net_device_stats stats; - uint tx_free; - spinlock_t lock; -}; - -static int scc_enet_open(struct net_device *dev); -static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int scc_enet_rx(struct net_device *dev); -static void scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); -static int scc_enet_close(struct net_device *dev); -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); - -/* These will be configurable for the SCC choice. -*/ -#define CPM_ENET_BLOCK CPM_CR_SCC1_SBLOCK -#define CPM_ENET_PAGE CPM_CR_SCC1_PAGE -#define PROFF_ENET PROFF_SCC1 -#define SCC_ENET 0 -#define SIU_INT_ENET SIU_INT_SCC1 - -/* These are both board and SCC dependent.... -*/ -#define PD_ENET_RXD ((uint)0x00000001) -#define PD_ENET_TXD ((uint)0x00000002) -#define PD_ENET_TENA ((uint)0x00000004) -#define PC_ENET_RENA ((uint)0x00020000) -#define PC_ENET_CLSN ((uint)0x00000004) -#define PC_ENET_TXCLK ((uint)0x00000800) -#define PC_ENET_RXCLK ((uint)0x00000400) -#define CMX_CLK_ROUTE ((uint)0x25000000) -#define CMX_CLK_MASK ((uint)0xff000000) - -/* Specific to a board. -*/ -#define PC_EST8260_ENET_LOOPBACK ((uint)0x80000000) -#define PC_EST8260_ENET_SQE ((uint)0x40000000) -#define PC_EST8260_ENET_NOTFD ((uint)0x20000000) - -static int -scc_enet_open(struct net_device *dev) -{ - - /* I should reset the ring buffers here, but I don't yet know - * a simple way to do that. - */ - netif_start_queue(dev); - return 0; /* Always succeed */ -} - -static int -scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - volatile cbd_t *bdp; - - - /* Fill in a Tx ring entry */ - bdp = cep->cur_tx; - -#ifndef final_version - if (!cep->tx_free || (bdp->cbd_sc & BD_ENET_TX_READY)) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since the tx queue should be stopped. - */ - printk("%s: tx queue full!.\n", dev->name); - return 1; - } -#endif - - /* Clear all of the status flags. - */ - bdp->cbd_sc &= ~BD_ENET_TX_STATS; - - /* If the frame is short, tell CPM to pad it. - */ - if (skb->len <= ETH_ZLEN) - bdp->cbd_sc |= BD_ENET_TX_PAD; - else - bdp->cbd_sc &= ~BD_ENET_TX_PAD; - - /* Set buffer length and buffer pointer. - */ - bdp->cbd_datlen = skb->len; - bdp->cbd_bufaddr = __pa(skb->data); - - /* Save skb pointer. - */ - cep->tx_skbuff[cep->skb_cur] = skb; - - cep->stats.tx_bytes += skb->len; - cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - - spin_lock_irq(&cep->lock); - - /* Send it on its way. Tell CPM its ready, interrupt when done, - * its the last BD of the frame, and to put the CRC on the end. - */ - bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); - - dev->trans_start = jiffies; - - /* If this was the last BD in the ring, start at the beginning again. - */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - if (!--cep->tx_free) - netif_stop_queue(dev); - - cep->cur_tx = (cbd_t *)bdp; - - spin_unlock_irq(&cep->lock); - - return 0; -} - -static void -scc_enet_timeout(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - printk("%s: transmit timed out.\n", dev->name); - cep->stats.tx_errors++; -#ifndef final_version - { - int i; - cbd_t *bdp; - printk(" Ring data dump: cur_tx %p tx_free %d cur_rx %p.\n", - cep->cur_tx, cep->tx_free, - cep->cur_rx); - bdp = cep->tx_bd_base; - printk(" Tx @base %p :\n", bdp); - for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - bdp = cep->rx_bd_base; - printk(" Rx @base %p :\n", bdp); - for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - } -#endif - if (cep->tx_free) - netif_wake_queue(dev); -} - -/* The interrupt handler. - * This is called from the CPM handler, not the MPC core interrupt. - */ -static void -scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - volatile struct scc_enet_private *cep; - volatile cbd_t *bdp; - ushort int_events; - int must_restart; - - cep = (struct scc_enet_private *)dev->priv; - - /* Get the interrupt events that caused us to be here. - */ - int_events = cep->sccp->scc_scce; - cep->sccp->scc_scce = int_events; - must_restart = 0; - - /* Handle receive event in its own function. - */ - if (int_events & SCCE_ENET_RXF) - scc_enet_rx(dev_id); - - /* Check for a transmit error. The manual is a little unclear - * about this, so the debug code until I get it figured out. It - * appears that if TXE is set, then TXB is not set. However, - * if carrier sense is lost during frame transmission, the TXE - * bit is set, "and continues the buffer transmission normally." - * I don't know if "normally" implies TXB is set when the buffer - * descriptor is closed.....trial and error :-). - */ - - /* Transmit OK, or non-fatal error. Update the buffer descriptors. - */ - if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { - spin_lock(&cep->lock); - bdp = cep->dirty_tx; - while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { - if (cep->tx_free == TX_RING_SIZE) - break; - - if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ - cep->stats.tx_heartbeat_errors++; - if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ - cep->stats.tx_window_errors++; - if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ - cep->stats.tx_aborted_errors++; - if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ - cep->stats.tx_fifo_errors++; - if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ - cep->stats.tx_carrier_errors++; - - - /* No heartbeat or Lost carrier are not really bad errors. - * The others require a restart transmit command. - */ - if (bdp->cbd_sc & - (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { - must_restart = 1; - cep->stats.tx_errors++; - } - - cep->stats.tx_packets++; - - /* Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (bdp->cbd_sc & BD_ENET_TX_DEF) - cep->stats.collisions++; - - /* Free the sk buffer associated with this last transmit. - */ - dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); - cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; - - /* Update pointer to next buffer descriptor to be transmitted. - */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - /* I don't know if we can be held off from processing these - * interrupts for more than one frame time. I really hope - * not. In such a case, we would now want to check the - * currently available BD (cur_tx) and determine if any - * buffers between the dirty_tx and cur_tx have also been - * sent. We would want to process anything in between that - * does not have BD_ENET_TX_READY set. - */ - - /* Since we have freed up a buffer, the ring is no longer - * full. - */ - if (!cep->tx_free++) { - if (netif_queue_stopped(dev)) { - netif_wake_queue(dev); - } - } - - cep->dirty_tx = (cbd_t *)bdp; - } - - if (must_restart) { - volatile cpm8260_t *cp; - - /* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. - */ - - cp = cpmp; - cp->cp_cpcr = - mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, - CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - } - spin_unlock(&cep->lock); - } - - /* Check for receive busy, i.e. packets coming but no place to - * put them. - */ - if (int_events & SCCE_ENET_BSY) - cep->stats.rx_dropped++; - - return; -} - -/* During a receive, the cur_rx points to the current incoming buffer. - * When we update through the ring, if the next incoming buffer has - * not been given to the system, we just set the empty indicator, - * effectively tossing the packet. - */ -static int -scc_enet_rx(struct net_device *dev) -{ - struct scc_enet_private *cep; - volatile cbd_t *bdp; - struct sk_buff *skb; - ushort pkt_len; - - cep = (struct scc_enet_private *)dev->priv; - - /* First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = cep->cur_rx; - -for (;;) { - if (bdp->cbd_sc & BD_ENET_RX_EMPTY) - break; - -#ifndef final_version - /* Since we have allocated space to hold a complete frame, both - * the first and last indicators should be set. - */ - if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != - (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) - printk("CPM ENET: rcv is not first+last\n"); -#endif - - /* Frame too long or too short. - */ - if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - cep->stats.rx_length_errors++; - if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ - cep->stats.rx_frame_errors++; - if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ - cep->stats.rx_crc_errors++; - if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ - cep->stats.rx_crc_errors++; - - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (bdp->cbd_sc & BD_ENET_RX_CL) { - cep->stats.rx_frame_errors++; - } - else { - - /* Process the incoming frame. - */ - cep->stats.rx_packets++; - pkt_len = bdp->cbd_datlen; - cep->stats.rx_bytes += pkt_len; - - /* This does 16 byte alignment, much more than we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - cep->stats.rx_dropped++; - } - else { - skb->dev = dev; - skb_put(skb,pkt_len-4); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len-4, 0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - } - - /* Clear the status flags for this buffer. - */ - bdp->cbd_sc &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty. - */ - bdp->cbd_sc |= BD_ENET_RX_EMPTY; - - /* Update BD pointer to next entry. - */ - if (bdp->cbd_sc & BD_ENET_RX_WRAP) - bdp = cep->rx_bd_base; - else - bdp++; - - } - cep->cur_rx = (cbd_t *)bdp; - - return 0; -} - -static int -scc_enet_close(struct net_device *dev) -{ - /* Don't know what to do yet. - */ - netif_stop_queue(dev); - - return 0; -} - -static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) -{ - struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; - - return &cep->stats; -} - -/* Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). - */ - -static void set_multicast_list(struct net_device *dev) -{ - struct scc_enet_private *cep; - struct dev_mc_list *dmi; - u_char *mcptr, *tdptr; - volatile scc_enet_t *ep; - int i, j; - cep = (struct scc_enet_private *)dev->priv; - - /* Get pointer to SCC area in parameter RAM. - */ - ep = (scc_enet_t *)dev->base_addr; - - if (dev->flags&IFF_PROMISC) { - - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_pmsr |= SCC_PSMR_PRO; - } else { - - cep->sccp->scc_pmsr &= ~SCC_PSMR_PRO; - - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's. - */ - ep->sen_gaddr1 = 0xffff; - ep->sen_gaddr2 = 0xffff; - ep->sen_gaddr3 = 0xffff; - ep->sen_gaddr4 = 0xffff; - } - else { - /* Clear filter and add the addresses in the list. - */ - ep->sen_gaddr1 = 0; - ep->sen_gaddr2 = 0; - ep->sen_gaddr3 = 0; - ep->sen_gaddr4 = 0; - - dmi = dev->mc_list; - - for (i=0; imc_count; i++, dmi = dmi->next) { - - /* Only support group multicast for now. - */ - if (!(dmi->dmi_addr[0] & 1)) - continue; - - /* The address in dmi_addr is LSB first, - * and taddr is MSB first. We have to - * copy bytes MSB first from dmi_addr. - */ - mcptr = (u_char *)dmi->dmi_addr + 5; - tdptr = (u_char *)&ep->sen_taddrh; - for (j=0; j<6; j++) - *tdptr++ = *mcptr--; - - /* Ask CPM to run CRC and set bit in - * filter mask. - */ - cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, - CPM_ENET_BLOCK, 0, - CPM_CR_SET_GADDR) | CPM_CR_FLG; - /* this delay is necessary here -- Cort */ - udelay(10); - while (cpmp->cp_cpcr & CPM_CR_FLG); - } - } - } -} - -/* Initialize the CPM Ethernet on SCC. - */ -int __init scc_enet_init(void) -{ - struct net_device *dev; - struct scc_enet_private *cep; - int i, j; - unsigned char *eap; - unsigned long mem_addr; - bd_t *bd; - volatile cbd_t *bdp; - volatile cpm8260_t *cp; - volatile scc_t *sccp; - volatile scc_enet_t *ep; - volatile immap_t *immap; - volatile iop8260_t *io; - - cp = cpmp; /* Get pointer to Communication Processor */ - - immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ - io = &immap->im_ioport; - - bd = (bd_t *)__res; - - /* Allocate some private information. - */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) - return -ENOMEM; - - __clear_user(cep,sizeof(*cep)); - spin_lock_init(&cep->lock); - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - - /* Get pointer to SCC area in parameter RAM. - */ - ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]); - - /* And another to the SCC register area. - */ - sccp = (volatile scc_t *)(&immap->im_scc[SCC_ENET]); - cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */ - - /* Disable receive and transmit in case someone left it running. - */ - sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - /* Configure port C and D pins for SCC Ethernet. This - * won't work for all SCC possibilities....it will be - * board/port specific. - */ - io->iop_pparc |= - (PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); - io->iop_pdirc &= - ~(PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); - io->iop_psorc &= - ~(PC_ENET_RENA | PC_ENET_TXCLK | PC_ENET_RXCLK); - io->iop_psorc |= PC_ENET_CLSN; - - io->iop_ppard |= (PD_ENET_RXD | PD_ENET_TXD | PD_ENET_TENA); - io->iop_pdird |= (PD_ENET_TXD | PD_ENET_TENA); - io->iop_pdird &= ~PD_ENET_RXD; - io->iop_psord |= PD_ENET_TXD; - io->iop_psord &= ~(PD_ENET_RXD | PD_ENET_TENA); - - /* Configure Serial Interface clock routing. - * First, clear all SCC bits to zero, then set the ones we want. - */ - immap->im_cpmux.cmx_scr &= ~CMX_CLK_MASK; - immap->im_cpmux.cmx_scr |= CMX_CLK_ROUTE; - - /* Allocate space for the buffer descriptors in the DP ram. - * These are relative offsets in the DP ram address space. - * Initialize base addresses for the buffer descriptors. - */ - i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); - ep->sen_genscc.scc_rbase = i; - cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - - i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); - ep->sen_genscc.scc_tbase = i; - cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - - cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; - cep->tx_free = TX_RING_SIZE; - cep->cur_rx = cep->rx_bd_base; - - ep->sen_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; - ep->sen_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; - - /* Set maximum bytes per receive buffer. - * This appears to be an Ethernet frame size, not the buffer - * fragment size. It must be a multiple of four. - */ - ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE; - - /* Set CRC preset and mask. - */ - ep->sen_cpres = 0xffffffff; - ep->sen_cmask = 0xdebb20e3; - - ep->sen_crcec = 0; /* CRC Error counter */ - ep->sen_alec = 0; /* alignment error counter */ - ep->sen_disfc = 0; /* discard frame counter */ - - ep->sen_pads = 0x8888; /* Tx short frame pad character */ - ep->sen_retlim = 15; /* Retry limit threshold */ - - ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ - ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ - - ep->sen_maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ - ep->sen_maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ - - /* Clear hash tables. - */ - ep->sen_gaddr1 = 0; - ep->sen_gaddr2 = 0; - ep->sen_gaddr3 = 0; - ep->sen_gaddr4 = 0; - ep->sen_iaddr1 = 0; - ep->sen_iaddr2 = 0; - ep->sen_iaddr3 = 0; - ep->sen_iaddr4 = 0; - - /* Set Ethernet station address. - * - * This is supplied in the board information structure, so we - * copy that into the controller. - */ - eap = (unsigned char *)&(ep->sen_paddrh); - for (i=5; i>=0; i--) - *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; - - ep->sen_pper = 0; /* 'cause the book says so */ - ep->sen_taddrl = 0; /* temp address (LSB) */ - ep->sen_taddrm = 0; - ep->sen_taddrh = 0; /* temp address (MSB) */ - - /* Now allocate the host memory pages and initialize the - * buffer descriptors. - */ - bdp = cep->tx_bd_base; - for (i=0; icbd_sc = 0; - bdp->cbd_bufaddr = 0; - bdp++; - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - bdp = cep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; - bdp->cbd_bufaddr = __pa(mem_addr); - mem_addr += CPM_ENET_RX_FRSIZE; - bdp++; - } - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* Let's re-initialize the channel now. We have to do it later - * than the manual describes because we have just now finished - * the BD initialization. - */ - cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - cep->skb_cur = cep->skb_dirty = 0; - - sccp->scc_scce = 0xffff; /* Clear any pending events */ - - /* Enable interrupts for transmit error, complete frame - * received, and any transmit buffer we have also set the - * interrupt flag. - */ - sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); - - /* Install our interrupt handler. - */ - request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev); - - /* Set GSMR_H to enable all normal operating modes. - * Set GSMR_L to enable Ethernet to MC68160. - */ - sccp->scc_gsmrh = 0; - sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); - - /* Set sync/delimiters. - */ - sccp->scc_dsr = 0xd555; - - /* Set processing mode. Use Ethernet CRC, catch broadcast, and - * start frame search 22 bit times after RENA. - */ - sccp->scc_pmsr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); - - /* It is now OK to enable the Ethernet transmitter. - * Unfortunately, there are board implementation differences here. - */ - io->iop_pparc &= ~(PC_EST8260_ENET_LOOPBACK | - PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); - io->iop_psorc &= ~(PC_EST8260_ENET_LOOPBACK | - PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); - io->iop_pdirc |= (PC_EST8260_ENET_LOOPBACK | - PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); - io->iop_pdatc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE); - io->iop_pdatc |= PC_EST8260_ENET_NOTFD; - - dev->base_addr = (unsigned long)ep; - dev->priv = cep; - - /* The CPM Ethernet specific entries in the device structure. */ - dev->open = scc_enet_open; - dev->hard_start_xmit = scc_enet_start_xmit; - dev->tx_timeout = scc_enet_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = scc_enet_close; - dev->get_stats = scc_enet_get_stats; - dev->set_multicast_list = set_multicast_list; - - /* And last, enable the transmit and receive processing. - */ - sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - - printk("%s: SCC ENET Version 0.1, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - - return 0; -} - diff -urN linux-2.4.25/arch/ppc/8260_io/fcc_enet.c linux-2.4.26/arch/ppc/8260_io/fcc_enet.c --- linux-2.4.25/arch/ppc/8260_io/fcc_enet.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/8260_io/fcc_enet.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,1613 +0,0 @@ -/* - * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. - * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) - * - * This version of the driver is a combination of the 8xx fec and - * 8260 SCC Ethernet drivers. People seem to be choosing common I/O - * configurations, so this driver will work on the EST8260 boards and - * others yet to be announced. - * - * Right now, I am very watseful with the buffers. I allocate memory - * pages and then divide them into 2K frame buffers. This way I know I - * have buffers large enough to hold one frame within one buffer descriptor. - * Once I get this working, I will use 64 or 128 byte CPM buffers, which - * will be much more memory efficient and will easily handle lots of - * small packets. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* The transmitter timeout - */ -#define TX_TIMEOUT (2*HZ) - -/* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it is best - * to keep them that size. - * We don't need to allocate pages for the transmitter. We just use - * the skbuffer directly. - */ -#define FCC_ENET_RX_PAGES 16 -#define FCC_ENET_RX_FRSIZE 2048 -#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE) -#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES) -#define TX_RING_SIZE 16 /* Must be power of two */ -#define TX_RING_MOD_MASK 15 /* for this to work */ - -/* The FCC stores dest/src/type, data, and checksum for receive packets. - */ -#define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 - -/* Maximum input DMA size. Must be a should(?) be a multiple of 4. -*/ -#define PKT_MAXDMA_SIZE 1520 - -/* Maximum input buffer size. Must be a multiple of 32. -*/ -#define PKT_MAXBLR_SIZE 1536 - -static int fcc_enet_open(struct net_device *dev); -static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int fcc_enet_rx(struct net_device *dev); -static void fcc_enet_mii(struct net_device *dev); -static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); -static int fcc_enet_close(struct net_device *dev); -static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void restart_fcc(struct net_device *dev); - -/* These will be configurable for the FCC choice. - * Multiple ports can be configured. There is little choice among the - * I/O pins to the PHY, except the clocks. We will need some board - * dependent clock selection. - * Why in the hell did I put these inside #ifdef's? I dunno, maybe to - * help show what pins are used for each device. - */ - -/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PA1_COL ((uint)0x00000001) -#define PA1_CRS ((uint)0x00000002) -#define PA1_TXER ((uint)0x00000004) -#define PA1_TXEN ((uint)0x00000008) -#define PA1_RXDV ((uint)0x00000010) -#define PA1_RXER ((uint)0x00000020) -#define PA1_TXDAT ((uint)0x00003c00) -#define PA1_RXDAT ((uint)0x0003c000) -#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) -#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ - PA1_RXDV | PA1_RXER) -#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) -#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) - -/* CLK12 is receive, CLK11 is transmit. These are board specific. -*/ -#define PC_F1RXCLK ((uint)0x00000800) -#define PC_F1TXCLK ((uint)0x00000400) -#define CMX1_CLK_ROUTE ((uint)0x3e000000) -#define CMX1_CLK_MASK ((uint)0xff000000) - -/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PB2_TXER ((uint)0x00000001) -#define PB2_RXDV ((uint)0x00000002) -#define PB2_TXEN ((uint)0x00000004) -#define PB2_RXER ((uint)0x00000008) -#define PB2_COL ((uint)0x00000010) -#define PB2_CRS ((uint)0x00000020) -#define PB2_TXDAT ((uint)0x000003c0) -#define PB2_RXDAT ((uint)0x00003c00) -#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ - PB2_RXER | PB2_RXDV | PB2_TXER) -#define PB2_PSORB1 (PB2_TXEN) -#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) -#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) - -/* CLK13 is receive, CLK14 is transmit. These are board dependent. -*/ -#define PC_F2RXCLK ((uint)0x00001000) -#define PC_F2TXCLK ((uint)0x00002000) -#define CMX2_CLK_ROUTE ((uint)0x00250000) -#define CMX2_CLK_MASK ((uint)0x00ff0000) - -/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, - * but there is little variation among the choices. - */ -#define PB3_RXDV ((uint)0x00004000) -#define PB3_RXER ((uint)0x00008000) -#define PB3_TXER ((uint)0x00010000) -#define PB3_TXEN ((uint)0x00020000) -#define PB3_COL ((uint)0x00040000) -#define PB3_CRS ((uint)0x00080000) -#define PB3_TXDAT ((uint)0x0f000000) -#define PB3_RXDAT ((uint)0x00f00000) -#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ - PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) -#define PB3_PSORB1 (0) -#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) -#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) - -/* CLK15 is receive, CLK16 is transmit. These are board dependent. -*/ -#define PC_F3RXCLK ((uint)0x00004000) -#define PC_F3TXCLK ((uint)0x00008000) -#define CMX3_CLK_ROUTE ((uint)0x00003700) -#define CMX3_CLK_MASK ((uint)0x0000ff00) - -/* MII status/control serial interface. -*/ -#define PC_MDIO ((uint)0x00400000) -#define PC_MDCK ((uint)0x00200000) - -/* A table of information for supporting FCCs. This does two things. - * First, we know how many FCCs we have and they are always externally - * numbered from zero. Second, it holds control register and I/O - * information that could be different among board designs. - */ -typedef struct fcc_info { - uint fc_fccnum; - uint fc_cpmblock; - uint fc_cpmpage; - uint fc_proff; - uint fc_interrupt; - uint fc_trxclocks; - uint fc_clockroute; - uint fc_clockmask; - uint fc_mdio; - uint fc_mdck; -} fcc_info_t; - -static fcc_info_t fcc_ports[] = { -#ifdef CONFIG_FCC1_ENET - { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1, - (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK, - PC_MDIO, PC_MDCK }, -#endif -#ifdef CONFIG_FCC2_ENET - { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2, - (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK, - PC_MDIO, PC_MDCK }, -#endif -#ifdef CONFIG_FCC3_ENET - { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3, - (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK, - PC_MDIO, PC_MDCK }, -#endif -}; - -/* The FCC buffer descriptors track the ring buffers. The rx_bd_base and - * tx_bd_base always point to the base of the buffer descriptors. The - * cur_rx and cur_tx point to the currently available buffer. - * The dirty_tx tracks the current buffer that is being sent by the - * controller. The cur_tx and dirty_tx are equal under both completely - * empty and completely full conditions. The empty/ready indicator in - * the buffer descriptor determines the actual condition. - */ -struct fcc_enet_private { - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - ushort skb_cur; - ushort skb_dirty; - - /* CPM dual port RAM relative addresses. - */ - cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ - cbd_t *tx_bd_base; - cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ - cbd_t *dirty_tx; /* The ring entries to be free()ed. */ - volatile fcc_t *fccp; - volatile fcc_enet_t *ep; - struct net_device_stats stats; - uint tx_full; - spinlock_t lock; - uint phy_address; - uint phy_type; - uint phy_duplex; - fcc_info_t *fip; -}; - -static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, - volatile immap_t *immap); -static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev); -static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, - volatile immap_t *immap); -static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, - volatile immap_t *immap); - -/* MII processing. We keep this as simple as possible. Requests are - * placed on the list (if there is room). When the request is finished - * by the MII, an optional function may be called. - */ -typedef struct mii_list { - uint mii_regval; - void (*mii_func)(uint val, struct net_device *dev); - struct mii_list *mii_next; -} mii_list_t; - -#define NMII 20 -mii_list_t mii_cmds[NMII]; -mii_list_t *mii_free; -mii_list_t *mii_head; -mii_list_t *mii_tail; - -static int phyaddr; -static uint phytype; - -static int mii_queue(int request, void (*func)(uint, struct net_device *)); -static void mii_startup_cmds(void); -static uint mii_send_receive(fcc_info_t *fip, uint cmd); - -/* Make MII read/write commands for the FCC. -*/ - -#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18)) - -#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \ - (REG & 0x1f) << 18)) - -#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \ - (REG & 0x1f) << 18) | \ - (VAL & 0xffff)) - - -static int -fcc_enet_open(struct net_device *dev) -{ - netif_start_queue(dev); - return 0; /* Always succeed */ -} - -static int -fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; - volatile cbd_t *bdp; - - - /* Fill in a Tx ring entry */ - bdp = cep->cur_tx; - -#ifndef final_version - if (bdp->cbd_sc & BD_ENET_TX_READY) { - /* Ooops. All transmit buffers are full. Bail out. - * This should not happen, since cep->tx_full should be set. - */ - printk("%s: tx queue full!.\n", dev->name); - return 1; - } -#endif - - /* Clear all of the status flags. - */ - bdp->cbd_sc &= ~BD_ENET_TX_STATS; - - /* If the frame is short, tell CPM to pad it. - */ - if (skb->len <= ETH_ZLEN) - bdp->cbd_sc |= BD_ENET_TX_PAD; - else - bdp->cbd_sc &= ~BD_ENET_TX_PAD; - - /* Set buffer length and buffer pointer. - */ - bdp->cbd_datlen = skb->len; - bdp->cbd_bufaddr = __pa(skb->data); - - /* Save skb pointer. - */ - cep->tx_skbuff[cep->skb_cur] = skb; - - cep->stats.tx_bytes += skb->len; - cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - - spin_lock_irq(&cep->lock); - - /* Send it on its way. Tell CPM its ready, interrupt when done, - * its the last BD of the frame, and to put the CRC on the end. - */ - bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); - -#if 0 - /* Errata says don't do this. - */ - cep->fccp->fcc_ftodr = 0x8000; -#endif - dev->trans_start = jiffies; - - /* If this was the last BD in the ring, start at the beginning again. - */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - if (bdp->cbd_sc & BD_ENET_TX_READY) { - netif_stop_queue(dev); - cep->tx_full = 1; - } - - cep->cur_tx = (cbd_t *)bdp; - - spin_unlock_irq(&cep->lock); - - return 0; -} - - -static void -fcc_enet_timeout(struct net_device *dev) -{ - struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; - - printk("%s: transmit timed out.\n", dev->name); - cep->stats.tx_errors++; -#ifndef final_version - { - int i; - cbd_t *bdp; - printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", - cep->cur_tx, cep->tx_full ? " (full)" : "", - cep->cur_rx); - bdp = cep->tx_bd_base; - printk(" Tx @base %p :\n", bdp); - for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - bdp = cep->rx_bd_base; - printk(" Rx @base %p :\n", bdp); - for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) - printk("%04x %04x %08x\n", - bdp->cbd_sc, - bdp->cbd_datlen, - bdp->cbd_bufaddr); - } -#endif - if (!cep->tx_full) - netif_wake_queue(dev); -} - -/* The interrupt handler. - */ -static void -fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - struct net_device *dev = dev_id; - volatile struct fcc_enet_private *cep; - volatile cbd_t *bdp; - ushort int_events; - int must_restart; - - cep = (struct fcc_enet_private *)dev->priv; - - /* Get the interrupt events that caused us to be here. - */ - int_events = cep->fccp->fcc_fcce; - cep->fccp->fcc_fcce = int_events; - must_restart = 0; - - /* Handle receive event in its own function. - */ - if (int_events & FCC_ENET_RXF) - fcc_enet_rx(dev_id); - - /* Check for a transmit error. The manual is a little unclear - * about this, so the debug code until I get it figured out. It - * appears that if TXE is set, then TXB is not set. However, - * if carrier sense is lost during frame transmission, the TXE - * bit is set, "and continues the buffer transmission normally." - * I don't know if "normally" implies TXB is set when the buffer - * descriptor is closed.....trial and error :-). - */ - - /* Transmit OK, or non-fatal error. Update the buffer descriptors. - */ - if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { - spin_lock(&cep->lock); - bdp = cep->dirty_tx; - while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { - if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) - break; - - if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ - cep->stats.tx_heartbeat_errors++; - if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ - cep->stats.tx_window_errors++; - if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ - cep->stats.tx_aborted_errors++; - if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ - cep->stats.tx_fifo_errors++; - if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ - cep->stats.tx_carrier_errors++; - - - /* No heartbeat or Lost carrier are not really bad errors. - * The others require a restart transmit command. - */ - if (bdp->cbd_sc & - (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { - must_restart = 1; - cep->stats.tx_errors++; - } - - cep->stats.tx_packets++; - - /* Deferred means some collisions occurred during transmit, - * but we eventually sent the packet OK. - */ - if (bdp->cbd_sc & BD_ENET_TX_DEF) - cep->stats.collisions++; - - /* Free the sk buffer associated with this last transmit. - */ - dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); - cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; - - /* Update pointer to next buffer descriptor to be transmitted. - */ - if (bdp->cbd_sc & BD_ENET_TX_WRAP) - bdp = cep->tx_bd_base; - else - bdp++; - - /* I don't know if we can be held off from processing these - * interrupts for more than one frame time. I really hope - * not. In such a case, we would now want to check the - * currently available BD (cur_tx) and determine if any - * buffers between the dirty_tx and cur_tx have also been - * sent. We would want to process anything in between that - * does not have BD_ENET_TX_READY set. - */ - - /* Since we have freed up a buffer, the ring is no longer - * full. - */ - if (cep->tx_full) { - cep->tx_full = 0; - if (netif_queue_stopped(dev)) { - netif_wake_queue(dev); - } - } - - cep->dirty_tx = (cbd_t *)bdp; - } - - if (must_restart) { - volatile cpm8260_t *cp; - - /* Some transmit errors cause the transmitter to shut - * down. We now issue a restart transmit. Since the - * errors close the BD and update the pointers, the restart - * _should_ pick up without having to reset any of our - * pointers either. - */ - - cp = cpmp; - cp->cp_cpcr = - mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, - 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - } - spin_unlock(&cep->lock); - } - - /* Check for receive busy, i.e. packets coming but no place to - * put them. - */ - if (int_events & FCC_ENET_BSY) { - cep->stats.rx_dropped++; - } - return; -} - -/* During a receive, the cur_rx points to the current incoming buffer. - * When we update through the ring, if the next incoming buffer has - * not been given to the system, we just set the empty indicator, - * effectively tossing the packet. - */ -static int -fcc_enet_rx(struct net_device *dev) -{ - struct fcc_enet_private *cep; - volatile cbd_t *bdp; - struct sk_buff *skb; - ushort pkt_len; - - cep = (struct fcc_enet_private *)dev->priv; - - /* First, grab all of the stats for the incoming packet. - * These get messed up if we get called due to a busy condition. - */ - bdp = cep->cur_rx; - -for (;;) { - if (bdp->cbd_sc & BD_ENET_RX_EMPTY) - break; - -#ifndef final_version - /* Since we have allocated space to hold a complete frame, both - * the first and last indicators should be set. - */ - if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != - (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) - printk("CPM ENET: rcv is not first+last\n"); -#endif - - /* Frame too long or too short. - */ - if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) - cep->stats.rx_length_errors++; - if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ - cep->stats.rx_frame_errors++; - if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ - cep->stats.rx_crc_errors++; - if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ - cep->stats.rx_crc_errors++; - - /* Report late collisions as a frame error. - * On this error, the BD is closed, but we don't know what we - * have in the buffer. So, just drop this frame on the floor. - */ - if (bdp->cbd_sc & BD_ENET_RX_CL) { - cep->stats.rx_frame_errors++; - } - else { - - /* Process the incoming frame. - */ - cep->stats.rx_packets++; - pkt_len = bdp->cbd_datlen; - cep->stats.rx_bytes += pkt_len; - - /* This does 16 byte alignment, much more than we need. - * The packet length includes FCS, but we don't want to - * include that when passing upstream as it messes up - * bridging applications. - */ - skb = dev_alloc_skb(pkt_len-4); - - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - cep->stats.rx_dropped++; - } - else { - skb->dev = dev; - skb_put(skb,pkt_len-4); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len-4, 0); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - } - } - - /* Clear the status flags for this buffer. - */ - bdp->cbd_sc &= ~BD_ENET_RX_STATS; - - /* Mark the buffer empty. - */ - bdp->cbd_sc |= BD_ENET_RX_EMPTY; - - /* Update BD pointer to next entry. - */ - if (bdp->cbd_sc & BD_ENET_RX_WRAP) - bdp = cep->rx_bd_base; - else - bdp++; - - } - cep->cur_rx = (cbd_t *)bdp; - - return 0; -} - -static int -fcc_enet_close(struct net_device *dev) -{ - /* Don't know what to do yet. - */ - netif_stop_queue(dev); - - return 0; -} - -static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev) -{ - struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; - - return &cep->stats; -} - -/* The MII is simulated from the 8xx FEC implementation. The FCC - * is not responsible for the MII control/status interface. - */ -static void -fcc_enet_mii(struct net_device *dev) -{ - struct fcc_enet_private *fep; - mii_list_t *mip; - uint mii_reg; - - fep = (struct fcc_enet_private *)dev->priv; -#if 0 - ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); - mii_reg = ep->fec_mii_data; -#endif - - if ((mip = mii_head) == NULL) { - printk("MII and no head!\n"); - return; - } - - if (mip->mii_func != NULL) - (*(mip->mii_func))(mii_reg, dev); - - mii_head = mip->mii_next; - mip->mii_next = mii_free; - mii_free = mip; - -#if 0 - if ((mip = mii_head) != NULL) - ep->fec_mii_data = mip->mii_regval; -#endif -} - -static int -mii_queue(int regval, void (*func)(uint, struct net_device *)) -{ - unsigned long flags; - mii_list_t *mip; - int retval; - - retval = 0; - - save_flags(flags); - cli(); - - if ((mip = mii_free) != NULL) { - mii_free = mip->mii_next; - mip->mii_regval = regval; - mip->mii_func = func; - mip->mii_next = NULL; - if (mii_head) { - mii_tail->mii_next = mip; - mii_tail = mip; - } - else { - mii_head = mii_tail = mip; -#if 0 - (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; -#endif - } - } - else { - retval = 1; - } - - restore_flags(flags); - - return(retval); -} - -static volatile uint full_duplex; - -static void -mii_status(uint mii_reg, struct net_device *dev) -{ - volatile uint prev_duplex; - - if (((mii_reg >> 18) & 0x1f) == 1) { - /* status register. - */ - printk("fec: "); - if (mii_reg & 0x0004) - printk("link up"); - else - printk("link down"); - - if (mii_reg & 0x0010) - printk(",remote fault"); - if (mii_reg & 0x0020) - printk(",auto complete"); - printk("\n"); - } - if (((mii_reg >> 18) & 0x1f) == 0x14) { - /* Extended chip status register. - */ - prev_duplex = full_duplex; - printk("fec: "); - if (mii_reg & 0x0800) - printk("100 Mbps"); - else - printk("10 Mbps"); - - if (mii_reg & 0x1000) { - printk(", Full-Duplex\n"); - full_duplex = 1; - } - else { - printk(", Half-Duplex\n"); - full_duplex = 0; - } -#if 0 - if (prev_duplex != full_duplex) - restart_fec(dev); -#endif - } - if (((mii_reg >> 18) & 0x1f) == 31) { - /* QS6612 PHY Control/Status. - * OK, now we have it all, so figure out what is going on. - */ - prev_duplex = full_duplex; - printk("fec: "); - - mii_reg = (mii_reg >> 2) & 7; - - if (mii_reg & 1) - printk("10 Mbps"); - else - printk("100 Mbps"); - - if (mii_reg > 4) { - printk(", Full-Duplex\n"); - full_duplex = 1; - } - else { - printk(", Half-Duplex\n"); - full_duplex = 0; - } - -#if 0 - if (prev_duplex != full_duplex) - restart_fec(dev); -#endif - } -} - -static uint phyno; - -static void -mii_discover_phy3(uint mii_reg, struct net_device *dev) -{ - phytype <<= 16; - phytype |= (mii_reg & 0xffff); - printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype); - mii_startup_cmds(); -} - -static void -mii_discover_phy(uint mii_reg, struct net_device *dev) -{ - if (phyno < 32) { - if ((phytype = (mii_reg & 0xffff)) != 0xffff) { - phyaddr = phyno; - mii_queue(mk_mii_read(3), mii_discover_phy3); - } - else { - phyno++; - mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy); - } - } - else { - printk("FEC: No PHY device found.\n"); - } -} - -static void -mii_discover_phy_poll(fcc_info_t *fip) -{ - uint rv; - int i; - - for (i=0; i<32; i++) { - rv = mii_send_receive(fip, mk_mii_phyaddr(i)); - if ((phytype = (rv & 0xffff)) != 0xffff) { - phyaddr = i; - rv = mii_send_receive(fip, mk_mii_read(3)); - phytype <<= 16; - phytype |= (rv & 0xffff); - printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype); - } - } -} - -static void -mii_startup_cmds(void) -{ - -#if 1 - /* Level One PHY. - */ - - /* Read status registers to clear any pending interrupt. - */ - mii_queue(mk_mii_read(1), mii_status); - mii_queue(mk_mii_read(18), mii_status); - - /* Read extended chip status register. - */ - mii_queue(mk_mii_read(0x14), mii_status); - - /* Set default operation of 100-TX....for some reason - * some of these bits are set on power up, which is wrong. - */ - mii_queue(mk_mii_write(0x13, 0), NULL); - - /* Enable Link status change interrupts. - */ - mii_queue(mk_mii_write(0x11, 0x0002), NULL); - - /* Don't advertize Full duplex. - mii_queue(mk_mii_write(0x04, 0x0021), NULL); - */ -#endif - -} - -/* This supports the mii_link interrupt below. - * We should get called three times. Once for register 1, once for - * register 18, and once for register 20. - */ -static uint mii_saved_reg1; - -static void -mii_relink(uint mii_reg, struct net_device *dev) -{ - volatile uint prev_duplex; - unsigned long flags; - - if (((mii_reg >> 18) & 0x1f) == 1) { - /* Just save the status register and get out. - */ - mii_saved_reg1 = mii_reg; - return; - } - if (((mii_reg >> 18) & 0x1f) == 18) { - /* Not much here, but has to be read to clear the - * interrupt condition. - */ - if ((mii_reg & 0x8000) == 0) - printk("fec: re-link and no IRQ?\n"); - if ((mii_reg & 0x4000) == 0) - printk("fec: no PHY power?\n"); - } - if (((mii_reg >> 18) & 0x1f) == 20) { - /* Extended chip status register. - * OK, now we have it all, so figure out what is going on. - */ - prev_duplex = full_duplex; - printk("fec: "); - if (mii_saved_reg1 & 0x0004) - printk("link up"); - else - printk("link down"); - - if (mii_saved_reg1 & 0x0010) - printk(", remote fault"); - if (mii_saved_reg1 & 0x0020) - printk(", auto complete"); - - if (mii_reg & 0x0800) - printk(", 100 Mbps"); - else - printk(", 10 Mbps"); - - if (mii_reg & 0x1000) { - printk(", Full-Duplex\n"); - full_duplex = 1; - } - else { - printk(", Half-Duplex\n"); - full_duplex = 0; - } - if (prev_duplex != full_duplex) { - save_flags(flags); - cli(); -#if 0 - restart_fec(dev); -#endif - restore_flags(flags); - } - } - if (((mii_reg >> 18) & 0x1f) == 31) { - /* QS6612 PHY Control/Status. - * OK, now we have it all, so figure out what is going on. - */ - prev_duplex = full_duplex; - printk("fec: "); - if (mii_saved_reg1 & 0x0004) - printk("link up"); - else - printk("link down"); - - if (mii_saved_reg1 & 0x0010) - printk(", remote fault"); - if (mii_saved_reg1 & 0x0020) - printk(", auto complete"); - - mii_reg = (mii_reg >> 2) & 7; - - if (mii_reg & 1) - printk(", 10 Mbps"); - else - printk(", 100 Mbps"); - - if (mii_reg > 4) { - printk(", Full-Duplex\n"); - full_duplex = 1; - } - else { - printk(", Half-Duplex\n"); - full_duplex = 0; - } - -#if 0 - if (prev_duplex != full_duplex) { - save_flags(flags); - cli(); - restart_fec(dev); - restore_flags(flags); - } -#endif - } -} - -/* Set or clear the multicast filter for this adaptor. - * Skeleton taken from sunlance driver. - * The CPM Ethernet implementation allows Multicast as well as individual - * MAC address filtering. Some of the drivers check to make sure it is - * a group multicast address, and discard those that are not. I guess I - * will do the same for now, but just remove the test if you want - * individual filtering as well (do the upper net layers want or support - * this kind of feature?). - */ -static void -set_multicast_list(struct net_device *dev) -{ - struct fcc_enet_private *cep; - struct dev_mc_list *dmi; - u_char *mcptr, *tdptr; - volatile fcc_enet_t *ep; - int i, j; - - cep = (struct fcc_enet_private *)dev->priv; - -return; - /* Get pointer to FCC area in parameter RAM. - */ - ep = (fcc_enet_t *)dev->base_addr; - - if (dev->flags&IFF_PROMISC) { - - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; - } else { - - cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; - - if (dev->flags & IFF_ALLMULTI) { - /* Catch all multicast addresses, so set the - * filter to all 1's. - */ - ep->fen_gaddrh = 0xffffffff; - ep->fen_gaddrl = 0xffffffff; - } - else { - /* Clear filter and add the addresses in the list. - */ - ep->fen_gaddrh = 0; - ep->fen_gaddrl = 0; - - dmi = dev->mc_list; - - for (i=0; imc_count; i++, dmi = dmi->next) { - - /* Only support group multicast for now. - */ - if (!(dmi->dmi_addr[0] & 1)) - continue; - - /* The address in dmi_addr is LSB first, - * and taddr is MSB first. We have to - * copy bytes MSB first from dmi_addr. - */ - mcptr = (u_char *)dmi->dmi_addr + 5; - tdptr = (u_char *)&ep->fen_taddrh; - for (j=0; j<6; j++) - *tdptr++ = *mcptr--; - - /* Ask CPM to run CRC and set bit in - * filter mask. - */ - cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, - cep->fip->fc_cpmblock, 0x0c, - CPM_CR_SET_GADDR) | CPM_CR_FLG; - udelay(10); - while (cpmp->cp_cpcr & CPM_CR_FLG); - } - } - } -} - -/* Initialize the CPM Ethernet on FCC. - */ -int __init fec_enet_init(void) -{ - struct net_device *dev; - struct fcc_enet_private *cep; - fcc_info_t *fip; - int i, np; - volatile immap_t *immap; - volatile iop8260_t *io; - - immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ - io = &immap->im_ioport; - - np = sizeof(fcc_ports) / sizeof(fcc_info_t); - fip = fcc_ports; - - while (np-- > 0) { - - /* Allocate some private information. - */ - cep = (struct fcc_enet_private *) - kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) - return -ENOMEM; - - __clear_user(cep,sizeof(*cep)); - spin_lock_init(&cep->lock); - cep->fip = fip; - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - dev->priv = cep; - - init_fcc_shutdown(fip, cep, immap); - init_fcc_ioports(fip, io, immap); - init_fcc_param(fip, dev, immap); - - dev->base_addr = (unsigned long)(cep->ep); - - /* The CPM Ethernet specific entries in the device - * structure. - */ - dev->open = fcc_enet_open; - dev->hard_start_xmit = fcc_enet_start_xmit; - dev->tx_timeout = fcc_enet_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = fcc_enet_close; - dev->get_stats = fcc_enet_get_stats; - dev->set_multicast_list = set_multicast_list; - - init_fcc_startup(fip, dev); - - printk("%s: FCC ENET Version 0.2, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); - - /* This is just a hack for now that works only on the EST - * board, or anything else that has MDIO/CK configured. - * It is mainly to test the MII software clocking. - */ - mii_discover_phy_poll(fip); - - fip++; - } - - return 0; -} - -/* Make sure the device is shut down during initialization. -*/ -static void __init -init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, - volatile immap_t *immap) -{ - volatile fcc_enet_t *ep; - volatile fcc_t *fccp; - - /* Get pointer to FCC area in parameter RAM. - */ - ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); - - /* And another to the FCC register area. - */ - fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); - cep->fccp = fccp; /* Keep the pointers handy */ - cep->ep = ep; - - /* Disable receive and transmit in case someone left it running. - */ - fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); -} - -/* Initialize the I/O pins for the FCC Ethernet. -*/ -static void __init -init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, - volatile immap_t *immap) -{ - - /* FCC1 pins are on port A/C. FCC2/3 are port B/C. - */ - if (fip->fc_proff == PROFF_FCC1) { - /* Configure port A and C pins for FCC1 Ethernet. - */ - io->iop_pdira &= ~PA1_DIRA0; - io->iop_pdira |= PA1_DIRA1; - io->iop_psora &= ~PA1_PSORA0; - io->iop_psora |= PA1_PSORA1; - io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1); - } - if (fip->fc_proff == PROFF_FCC2) { - /* Configure port B and C pins for FCC Ethernet. - */ - io->iop_pdirb &= ~PB2_DIRB0; - io->iop_pdirb |= PB2_DIRB1; - io->iop_psorb &= ~PB2_PSORB0; - io->iop_psorb |= PB2_PSORB1; - io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1); - } - if (fip->fc_proff == PROFF_FCC3) { - /* Configure port B and C pins for FCC Ethernet. - */ - io->iop_pdirb &= ~PB3_DIRB0; - io->iop_pdirb |= PB3_DIRB1; - io->iop_psorb &= ~PB3_PSORB0; - io->iop_psorb |= PB3_PSORB1; - io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1); - } - - /* Port C has clocks...... - */ - io->iop_psorc &= ~(fip->fc_trxclocks); - io->iop_pdirc &= ~(fip->fc_trxclocks); - io->iop_pparc |= fip->fc_trxclocks; - - /* ....and the MII serial clock/data. - */ - io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); - io->iop_podrc |= fip->fc_mdio; - io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); - io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck); - - /* Configure Serial Interface clock routing. - * First, clear all FCC bits to zero, - * then set the ones we want. - */ - immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); - immap->im_cpmux.cmx_fcr |= fip->fc_clockroute; -} - -static void __init -init_fcc_param(fcc_info_t *fip, struct net_device *dev, - volatile immap_t *immap) -{ - unsigned char *eap; - unsigned long mem_addr; - bd_t *bd; - int i, j; - struct fcc_enet_private *cep; - volatile fcc_enet_t *ep; - volatile cbd_t *bdp; - volatile cpm8260_t *cp; - - cep = (struct fcc_enet_private *)(dev->priv); - ep = cep->ep; - cp = cpmp; - - bd = (bd_t *)__res; - - /* Zero the whole thing.....I must have missed some individually. - * It works when I do this. - */ - memset((char *)ep, 0, sizeof(fcc_enet_t)); - - /* Allocate space for the buffer descriptors in the DP ram. - * These are relative offsets in the DP ram address space. - * Initialize base addresses for the buffer descriptors. - */ -#if 0 - /* I really want to do this, but for some reason it doesn't - * work with the data cache enabled, so I allocate from the - * main memory instead. - */ - i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); - ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i]; - cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - - i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); - ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i]; - cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; -#else - cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); - ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); - cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); - ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); -#endif - - cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; - cep->cur_rx = cep->rx_bd_base; - - ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; - ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; - - /* Set maximum bytes per receive buffer. - * It must be a multiple of 32. - */ - ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; - - /* Allocate space in the reserved FCC area of DPRAM for the - * internal buffers. No one uses this space (yet), so we - * can do this. Later, we will add resource management for - * this area. - */ - mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); - ep->fen_genfcc.fcc_riptr = mem_addr; - ep->fen_genfcc.fcc_tiptr = mem_addr+32; - ep->fen_padptr = mem_addr+64; - memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); - - ep->fen_genfcc.fcc_rbptr = 0; - ep->fen_genfcc.fcc_tbptr = 0; - ep->fen_genfcc.fcc_rcrc = 0; - ep->fen_genfcc.fcc_tcrc = 0; - ep->fen_genfcc.fcc_res1 = 0; - ep->fen_genfcc.fcc_res2 = 0; - - ep->fen_camptr = 0; /* CAM isn't used in this driver */ - - /* Set CRC preset and mask. - */ - ep->fen_cmask = 0xdebb20e3; - ep->fen_cpres = 0xffffffff; - - ep->fen_crcec = 0; /* CRC Error counter */ - ep->fen_alec = 0; /* alignment error counter */ - ep->fen_disfc = 0; /* discard frame counter */ - ep->fen_retlim = 15; /* Retry limit threshold */ - ep->fen_pper = 0; /* Normal persistence */ - - /* Clear hash filter tables. - */ - ep->fen_gaddrh = 0; - ep->fen_gaddrl = 0; - ep->fen_iaddrh = 0; - ep->fen_iaddrl = 0; - - /* Clear the Out-of-sequence TxBD. - */ - ep->fen_tfcstat = 0; - ep->fen_tfclen = 0; - ep->fen_tfcptr = 0; - - ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ - ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ - - /* Set Ethernet station address. - * - * This is supplied in the board information structure, so we - * copy that into the controller. - * So, far we have only been given one Ethernet address. We make - * it unique by setting a few bits in the upper byte of the - * non-static part of the address. - */ - eap = (unsigned char *)&(ep->fen_paddrh); - for (i=5; i>=0; i--) { - -/* - * The EP8260 only uses FCC3, so we can safely give it the real - * MAC address. - */ -#ifndef CONFIG_RPX6 - if (i == 3) { - dev->dev_addr[i] = bd->bi_enetaddr[i]; - dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); - *eap++ = dev->dev_addr[i]; - } - else { - *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; - } -#else - *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; -#endif - } - - ep->fen_taddrh = 0; - ep->fen_taddrm = 0; - ep->fen_taddrl = 0; - - ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ - ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ - - /* Clear stat counters, in case we ever enable RMON. - */ - ep->fen_octc = 0; - ep->fen_colc = 0; - ep->fen_broc = 0; - ep->fen_mulc = 0; - ep->fen_uspc = 0; - ep->fen_frgc = 0; - ep->fen_ospc = 0; - ep->fen_jbrc = 0; - ep->fen_p64c = 0; - ep->fen_p65c = 0; - ep->fen_p128c = 0; - ep->fen_p256c = 0; - ep->fen_p512c = 0; - ep->fen_p1024c = 0; - - ep->fen_rfthr = 0; /* Suggested by manual */ - ep->fen_rfcnt = 0; - ep->fen_cftype = 0; - - /* Now allocate the host memory pages and initialize the - * buffer descriptors. - */ - bdp = cep->tx_bd_base; - for (i=0; icbd_sc = 0; - bdp->cbd_datlen = 0; - bdp->cbd_bufaddr = 0; - bdp++; - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - bdp = cep->rx_bd_base; - for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; - bdp->cbd_datlen = 0; - bdp->cbd_bufaddr = __pa(mem_addr); - mem_addr += FCC_ENET_RX_FRSIZE; - bdp++; - } - } - - /* Set the last buffer to wrap. - */ - bdp--; - bdp->cbd_sc |= BD_SC_WRAP; - - /* Let's re-initialize the channel now. We have to do it later - * than the manual describes because we have just now finished - * the BD initialization. - */ - cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - cep->skb_cur = cep->skb_dirty = 0; -} - -/* Let 'er rip. -*/ -static void __init -init_fcc_startup(fcc_info_t *fip, struct net_device *dev) -{ - volatile fcc_t *fccp; - struct fcc_enet_private *cep; - - cep = (struct fcc_enet_private *)(dev->priv); - fccp = cep->fccp; - - fccp->fcc_fcce = 0xffff; /* Clear any pending events */ - - /* Enable interrupts for transmit error, complete frame - * received, and any transmit buffer we have also set the - * interrupt flag. - */ - fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); - - /* Install our interrupt handler. - */ - if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet", - dev) < 0) - printk("Can't get FCC IRQ %d\n", fip->fc_interrupt); - - /* Set GFMR to enable Ethernet operating mode. - */ - fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); - - /* Set sync/delimiters. - */ - fccp->fcc_fdsr = 0xd555; - - /* Set protocol specific processing mode for Ethernet. - * This has to be adjusted for Full Duplex operation after we can - * determine how to detect that. - */ - fccp->fcc_fpsmr = FCC_PSMR_ENCRC; - - /* And last, enable the transmit and receive processing. - */ - fccp->fcc_gfmr |= (FCC_GFMR_ENR | FCC_GFMR_ENT); -} - -/* MII command/status interface. - * I'm not going to describe all of the details. You can find the - * protocol definition in many other places, including the data sheet - * of most PHY parts. - * I wonder what "they" were thinking (maybe weren't) when they leave - * the I2C in the CPM but I have to toggle these bits...... - */ -static uint -mii_send_receive(fcc_info_t *fip, uint cmd) -{ - unsigned long flags; - uint retval; - int read_op, i; - volatile immap_t *immap; - volatile iop8260_t *io; - - immap = (immap_t *)IMAP_ADDR; - io = &immap->im_ioport; - - /* When we get here, both clock and data are high, outputs. - * Output is open drain. - * Data transitions on high->low clock, is valid on low->high clock. - * Spec says edge transitions no closer than 160 nSec, minimum clock - * cycle 400 nSec. I could only manage about 500 nSec edges with - * an XOR loop, so I won't worry about delays yet. - * I disable interrupts during bit flipping to ensure atomic - * updates of the registers. I do lots of interrupt disable/enable - * to ensure we don't hang out too long with interrupts disabled. - */ - - /* First, crank out 32 1-bits as preamble. - * This is 64 transitions to clock the bits, with clock/data - * left high. - */ - save_flags(flags); - cli(); - for (i=0; i<64; i++) { - io->iop_pdatc ^= fip->fc_mdck; - udelay(0); - } - restore_flags(flags); - - read_op = ((cmd & 0xf0000000) == 0x60000000); - - /* We return the command word on a write op, or the command portion - * plus the new data on a read op. This is what the 8xx FEC does, - * and it allows the functions to simply look at the returned value - * and know the PHY/register as well. - */ - if (read_op) - retval = cmd; - else - retval = (cmd >> 16); - - /* Clock out the first 16 MS bits of the command. - */ - save_flags(flags); - cli(); - for (i=0; i<16; i++) { - io->iop_pdatc &= ~(fip->fc_mdck); - if (cmd & 0x80000000) - io->iop_pdatc |= fip->fc_mdio; - else - io->iop_pdatc &= ~(fip->fc_mdio); - cmd <<= 1; - io->iop_pdatc |= fip->fc_mdck; - udelay(0); - } - - /* Do the turn-around. If read op, we make the IO and input. - * If write op, do the 1/0 thing. - */ - io->iop_pdatc &= ~(fip->fc_mdck); - if (read_op) - io->iop_pdirc &= ~(fip->fc_mdio); - else - io->iop_pdatc |= fip->fc_mdio; - io->iop_pdatc |= fip->fc_mdck; - - /* I do this mainly to get just a little delay. - */ - restore_flags(flags); - save_flags(flags); - cli(); - io->iop_pdatc &= ~(fip->fc_mdck); - io->iop_pdirc &= ~(fip->fc_mdio); - io->iop_pdatc |= fip->fc_mdck; - - restore_flags(flags); - save_flags(flags); - cli(); - - /* For read, clock in 16 bits. For write, clock out - * rest of command. - */ - if (read_op) { - io->iop_pdatc &= ~(fip->fc_mdck); - udelay(0); - for (i=0; i<16; i++) { - io->iop_pdatc |= fip->fc_mdck; - udelay(0); - retval <<= 1; - if (io->iop_pdatc & fip->fc_mdio) - retval |= 1; - io->iop_pdatc &= ~(fip->fc_mdck); - udelay(0); - } - } - else { - for (i=0; i<16; i++) { - io->iop_pdatc &= ~(fip->fc_mdck); - if (cmd & 0x80000000) - io->iop_pdatc |= fip->fc_mdio; - else - io->iop_pdatc &= ~(fip->fc_mdio); - cmd <<= 1; - io->iop_pdatc |= fip->fc_mdck; - udelay(0); - } - io->iop_pdatc &= ~(fip->fc_mdck); - } - restore_flags(flags); - - /* Some diagrams show two 1 bits for "idle". I don't know if - * this is really necessary or if it was just to indicate nothing - * is going to happen for a while. - * Make the data pin an output, set the data high, and clock it. - */ - save_flags(flags); - cli(); - io->iop_pdatc |= fip->fc_mdio; - io->iop_pdirc |= fip->fc_mdio; - for (i=0; i<3; i++) - io->iop_pdatc ^= fip->fc_mdck; - restore_flags(flags); - - /* We exit with the same conditions as entry. - */ - return(retval); -} diff -urN linux-2.4.25/arch/ppc/8260_io/uart.c linux-2.4.26/arch/ppc/8260_io/uart.c --- linux-2.4.25/arch/ppc/8260_io/uart.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/8260_io/uart.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,2787 +0,0 @@ -/* - * UART driver for MPC8260 CPM SCC or SMC - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) - * Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com) - * 2.3.99 updates - * - * I used the 8xx uart.c driver as the framework for this driver. - * The original code was written for the EST8260 board. I tried to make - * it generic, but there may be some assumptions in the structures that - * have to be fixed later. - * - * The 8xx and 8260 are similar, but not identical. Over time we - * could probably merge these two drivers. - * To save porting time, I did not bother to change any object names - * that are not accessed outside of this file. - * It still needs lots of work........When it was easy, I included code - * to support the SCCs. - * Only the SCCs support modem control, so that is not complete either. - * - * This module exports the following rs232 io functions: - * - * int rs_8xx_init(void); - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_MAGIC_SYSRQ -#include -#endif - -#ifdef CONFIG_SERIAL_CONSOLE -#include - -/* this defines the index into rs_table for the port to use -*/ -#ifndef CONFIG_SERIAL_CONSOLE_PORT -#define CONFIG_SERIAL_CONSOLE_PORT 0 -#endif -#endif - -#define TX_WAKEUP ASYNC_SHARE_IRQ - -static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.01"; - -static DECLARE_TASK_QUEUE(tq_serial); - -static struct tty_driver serial_driver, callout_driver; -static int serial_refcount; -static int serial_console_setup(struct console *co, char *options); - -static void serial_console_write(struct console *c, const char *s, - unsigned count); -static kdev_t serial_console_device(struct console *c); - -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -static unsigned long break_pressed; /* break, really ... */ -#endif - -/* - * Serial driver configuration section. Here are the various options: - */ -#define SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - -#define _INLINE_ inline - -#define DBG_CNT(s) - -/* We overload some of the items in the data structure to meet our - * needs. For example, the port address is the CPM parameter ram - * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and - * 2 SMCs. The "hub6" field is used to indicate the channel number, with - * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs. - * Since these ports are so versatile, I don't yet have a strategy for - * their management. For example, SCC1 is used for Ethernet. Right - * now, just don't put them in the table. Of course, right now I just - * want the SMC to work as a uart :-).. - * The "type" field is currently set to 0, for PORT_UNKNOWN. It is - * not currently used. I should probably use it to indicate the port - * type of CMS or SCC. - * The SMCs do not support any modem control signals. - */ -#define smc_scc_num hub6 - -/* SMC2 is sometimes used for low performance TDM interfaces. Define - * this as 1 if you want SMC2 as a serial port UART managed by this driver. - * Define this as 0 if you wish to use SMC2 for something else. - */ -#define USE_SMC2 1 - -/* Define SCC to ttySx mapping. -*/ -#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ - -/* Define which SCC is the first one to use for a serial port. These - * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used - * for Ethernet, and the first available SCC for serial UART is SCC2. - * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and - * interrupt vectors in the table below to match. - */ -#define SCC_IDX_BASE 1 /* table index */ - -static struct serial_state rs_table[] = { - /* UART CLK PORT IRQ FLAGS NUM */ - { 0, 0, PROFF_SMC1, SIU_INT_SMC1, 0, 0 }, /* SMC1 ttyS0 */ -#if USE_SMC2 - { 0, 0, PROFF_SMC2, SIU_INT_SMC2, 0, 1 }, /* SMC2 ttyS1 */ -#endif - { 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE}, /* SCC2 ttyS2 */ - { 0, 0, PROFF_SCC3, SIU_INT_SCC3, 0, SCC_NUM_BASE + 1}, /* SCC3 ttyS3 */ -}; - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) - -static struct tty_struct *serial_table[NR_PORTS]; -static struct termios *serial_termios[NR_PORTS]; -static struct termios *serial_termios_locked[NR_PORTS]; - -/* The number of buffer descriptors and their sizes. -*/ -#define RX_NUM_FIFO 4 -#define RX_BUF_SIZE 32 -#define TX_NUM_FIFO 4 -#define TX_BUF_SIZE 32 - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* The async_struct in serial.h does not really give us what we - * need, so define our own here. - */ -typedef struct serial_info { - int magic; - int flags; - struct serial_state *state; - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int line; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; - int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ - struct tq_struct tqueue; - struct tq_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - /* CPM Buffer Descriptor pointers. - */ - cbd_t *rx_bd_base; - cbd_t *rx_cur; - cbd_t *tx_bd_base; - cbd_t *tx_cur; -} ser_info_t; - -static struct console sercons = { - name: "ttyS", - write: serial_console_write, - device: serial_console_device, - setup: serial_console_setup, - flags: CON_PRINTBUFFER, - index: CONFIG_SERIAL_CONSOLE_PORT, -}; - - -static void change_speed(ser_info_t *info); -static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout); - -static inline int serial_paranoia_check(ser_info_t *info, - kdev_t device, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, kdevname(device), routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, kdevname(device), routine); - return 1; - } -#endif - return 0; -} - -/* - * This is used to figure out the divisor speeds and the timeouts, - * indexed by the termio value. The generic CPM functions are responsible - * for setting and assigning baud rate generators for us. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; - - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_8xx_stop(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile scc_t *sccp; - volatile smc_t *smcp; - - if (serial_paranoia_check(info, tty->device, "rs_stop")) - return; - - save_flags(flags); cli(); - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - smcp->smc_smcm &= ~SMCM_TX; - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - sccp->scc_sccm &= ~UART_SCCM_TX; - } - restore_flags(flags); -} - -static void rs_8xx_start(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int idx; - unsigned long flags; - volatile scc_t *sccp; - volatile smc_t *smcp; - - if (serial_paranoia_check(info, tty->device, "rs_stop")) - return; - - save_flags(flags); cli(); - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - smcp->smc_smcm |= SMCM_TX; - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - sccp->scc_sccm |= UART_SCCM_TX; - } - restore_flags(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static _INLINE_ void rs_sched_event(ser_info_t *info, - int event) -{ - info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); -} - -static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs) -{ - struct tty_struct *tty = info->tty; - unsigned char ch, *cp; - /*int ignored = 0;*/ - int i; - ushort status; - struct async_icount *icount; - volatile cbd_t *bdp; - - icount = &info->state->icount; - - /* Just loop through the closed BDs and copy the characters into - * the buffer. - */ - bdp = info->rx_cur; - for (;;) { - if (bdp->cbd_sc & BD_SC_EMPTY) /* If this one is empty */ - break; /* we are all done */ - - /* The read status mask tell us what we should do with - * incoming characters, especially if errors occur. - * One special case is the use of BD_SC_EMPTY. If - * this is not set, we are supposed to be ignoring - * inputs. In this case, just mark the buffer empty and - * continue. - if (!(info->read_status_mask & BD_SC_EMPTY)) { - bdp->cbd_sc |= BD_SC_EMPTY; - bdp->cbd_sc &= - ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - continue; - } - */ - - /* Get the number of characters and the buffer pointer. - */ - i = bdp->cbd_datlen; - cp = (unsigned char *)__va(bdp->cbd_bufaddr); - status = bdp->cbd_sc; - - /* Check to see if there is room in the tty buffer for - * the characters in our BD buffer. If not, we exit - * now, leaving the BD with the characters. We'll pick - * them up again on the next receive interrupt (which could - * be a timeout). - */ - if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) - break; - - while (i-- > 0) { - ch = *cp++; - *tty->flip.char_buf_ptr = ch; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, *status); -#endif - *tty->flip.flag_buf_ptr = 0; - if (status & (BD_SC_BR | BD_SC_FR | - BD_SC_PR | BD_SC_OV)) { - /* - * For statistics only - */ - if (status & BD_SC_BR) - icount->brk++; - else if (status & BD_SC_PR) - icount->parity++; - else if (status & BD_SC_FR) - icount->frame++; - if (status & BD_SC_OV) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - if (status & info->ignore_status_mask) { - if (++ignored > 100) - break; - continue; - } - */ - status &= info->read_status_mask; - - if (status & (BD_SC_BR)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (status & BD_SC_PR) - *tty->flip.flag_buf_ptr = TTY_PARITY; - else if (status & BD_SC_FR) - *tty->flip.flag_buf_ptr = TTY_FRAME; - if (status & BD_SC_OV) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = - TTY_OVERRUN; - } - } - } - -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (break_pressed && info->line == sercons.index) { - if (ch != 0 && time_before(jiffies, - break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); - break_pressed = 0; - goto ignore_char; - } else - break_pressed = 0; - } -#endif - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - } - -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - ignore_char: -#endif - - /* This BD is ready to be used again. Clear status. - * Get next BD. - */ - bdp->cbd_sc |= BD_SC_EMPTY; - bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); - - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->rx_bd_base; - else - bdp++; - } - - info->rx_cur = (cbd_t *)bdp; - - queue_task(&tty->flip.tqueue, &tq_timer); -} - -static _INLINE_ void receive_break(ser_info_t *info, struct pt_regs *regs) -{ - struct tty_struct *tty = info->tty; - - info->state->icount.brk++; - -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - return; - } else - break_pressed = 0; - } -#endif - - /* Check to see if there is room in the tty buffer for - * the break. If not, we exit now, losing the break. FIXME - */ - if ((tty->flip.count + 1) >= TTY_FLIPBUF_SIZE) - return; - *(tty->flip.flag_buf_ptr++) = TTY_BREAK; - *(tty->flip.char_buf_ptr++) = 0; - tty->flip.count++; - - queue_task(&tty->flip.tqueue, &tq_timer); -} - - -static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs) -{ - - if (info->flags & TX_WAKEUP) { - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - } - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif -} - -#ifdef notdef - /* I need to do this for the SCCs, so it is left as a reminder. - */ -static _INLINE_ void check_modem_status(struct async_struct *info) -{ - int status; - struct async_icount *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->state->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { -#ifdef SERIAL_DEBUG_OPEN - printk("scheduling hangup..."); -#endif - MOD_INC_USE_COUNT; - if (schedule_task(&info->tqueue_hangup) == 0) - MOD_DEC_USE_COUNT; - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} -#endif - -/* - * This is the serial driver's interrupt routine for a single port - */ -static void rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * regs) -{ - u_char events; - int idx; - ser_info_t *info; - volatile smc_t *smcp; - volatile scc_t *sccp; - - info = (ser_info_t *)dev_id; - - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - events = smcp->smc_smce; - if (events & SMCM_BRKE) - receive_break(info, regs); - if (events & SMCM_RX) - receive_chars(info, regs); - if (events & SMCM_TX) - transmit_chars(info, regs); - smcp->smc_smce = events; - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - events = sccp->scc_scce; - if (events & SMCM_BRKE) - receive_break(info, regs); - if (events & SCCM_RX) - receive_chars(info, regs); - if (events & SCCM_TX) - transmit_chars(info, regs); - sccp->scc_scce = events; - } - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_single(%d, %x)...", - info->state->smc_scc_num, events); -#endif -#ifdef modem_control - check_modem_status(info); -#endif - info->last_active = jiffies; -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) -{ - ser_info_t *info = (ser_info_t *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } -} - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void do_serial_hangup(void *private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (tty) - tty_hangup(tty); - MOD_DEC_USE_COUNT; -} - -/*static void rs_8xx_timer(void) -{ - printk("rs_8xx_timer\n"); -}*/ - - -static int startup(ser_info_t *info) -{ - unsigned long flags; - int retval=0; - int idx; - struct serial_state *state= info->state; - volatile smc_t *smcp; - volatile scc_t *sccp; - volatile smc_uart_t *up; - volatile scc_uart_t *scup; - - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - goto errout; - } - -#ifdef maybe - if (!state->port || !state->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - goto errout; - } -#endif - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); -#endif - - -#ifdef modem_control - info->MCR = 0; - if (info->tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#endif - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - - /* - * and set the speed of the serial port - */ - change_speed(info); - - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - - /* Enable interrupts and I/O. - */ - smcp->smc_smcm |= (SMCM_RX | SMCM_TX); - smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); - - /* We can tune the buffer length and idle characters - * to take advantage of the entire incoming buffer size. - * If mrblr is something other than 1, maxidl has to be - * non-zero or we never get an interrupt. The maxidl - * is the number of character times we wait after reception - * of the last character before we decide no more characters - * are coming. - */ - up = (smc_uart_t *)&immr->im_dprambase[state->port]; -#if 0 - up->smc_mrblr = 1; /* receive buffer length */ - up->smc_maxidl = 0; /* wait forever for next char */ -#else - up->smc_mrblr = RX_BUF_SIZE; - up->smc_maxidl = RX_BUF_SIZE; -#endif - up->smc_brkcr = 1; /* number of break chars */ - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - scup = (scc_uart_t *)&immr->im_dprambase[state->port]; -#if 0 - scup->scc_genscc.scc_mrblr = 1; /* receive buffer length */ - scup->scc_maxidl = 0; /* wait forever for next char */ -#else - scup->scc_genscc.scc_mrblr = RX_BUF_SIZE; - scup->scc_maxidl = RX_BUF_SIZE; -#endif - - sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); - } - - info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); - return 0; - -errout: - restore_flags(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(ser_info_t * info) -{ - unsigned long flags; - struct serial_state *state; - int idx; - volatile smc_t *smcp; - volatile scc_t *sccp; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - state = info->state; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); -#endif - - save_flags(flags); cli(); /* Disable interrupts */ - - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - - /* Disable interrupts and I/O. - */ - smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); -#ifdef CONFIG_SERIAL_CONSOLE - /* We can't disable the transmitter if this is the - * system console. - */ - if (idx != CONFIG_SERIAL_CONSOLE_PORT) -#endif - smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); - sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); - } - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(ser_info_t *info) -{ - int baud_rate; - unsigned cflag, cval, scval, prev_mode; - int i, bits, sbits, idx; - unsigned long flags; - volatile smc_t *smcp; - volatile scc_t *sccp; - - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; - - /* Character length programmed into the mode register is the - * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, - * 1 or 2 stop bits, minus 1. - * The value 'bits' counts this for us. - */ - cval = 0; - scval = 0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: bits = 5; break; - case CS6: bits = 6; break; - case CS7: bits = 7; break; - case CS8: bits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: bits = 8; break; - } - sbits = bits - 5; - - if (cflag & CSTOPB) { - cval |= SMCMR_SL; /* Two stops */ - scval |= SCU_PMSR_SL; - bits++; - } - if (cflag & PARENB) { - cval |= SMCMR_PEN; - scval |= SCU_PMSR_PEN; - bits++; - } - if (!(cflag & PARODD)) { - cval |= SMCMR_PM_EVEN; - scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); - } - - /* Determine divisor based on baud rate */ - i = cflag & CBAUD; - if (i >= (sizeof(baud_table)/sizeof(int))) - baud_rate = 9600; - else - baud_rate = baud_table[i]; - - info->timeout = (TX_BUF_SIZE*HZ*bits); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - -#ifdef modem_control - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); -#endif - - /* - * Set up parity check flag - */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); - if (I_INPCK(info->tty)) - info->read_status_mask |= BD_SC_FR | BD_SC_PR; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) - info->read_status_mask |= BD_SC_BR; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; - if (I_IGNBRK(info->tty)) { - info->ignore_status_mask |= BD_SC_BR; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= BD_SC_OV; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->read_status_mask &= ~BD_SC_EMPTY; - save_flags(flags); cli(); - - /* Start bit has not been added (so don't, because we would just - * subtract it later), and we need to add one for the number of - * stops bits (there is always at least one). - */ - bits++; - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - - /* Set the mode register. We want to keep a copy of the - * enables, because we want to put them back if they were - * present. - */ - prev_mode = smcp->smc_smcmr & (SMCMR_REN | SMCMR_TEN); - smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART - | prev_mode; - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - sccp->scc_pmsr = (sbits << 12) | scval; - } - - m8260_cpm_setbrg(info->state->smc_scc_num, baud_rate); - - restore_flags(flags); -} - -static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile cbd_t *bdp; - - if (serial_paranoia_check(info, tty->device, "rs_put_char")) - return; - - if (!tty) - return; - - bdp = info->tx_cur; - while (bdp->cbd_sc & BD_SC_READY); - - *((char *)__va(bdp->cbd_bufaddr)) = ch; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (cbd_t *)bdp; - -} - -static int rs_8xx_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, ret = 0; - ser_info_t *info = (ser_info_t *)tty->driver_data; - volatile cbd_t *bdp; - - if (serial_paranoia_check(info, tty->device, "rs_write")) - return 0; - - if (!tty) - return 0; - - bdp = info->tx_cur; - - while (1) { - c = MIN(count, TX_BUF_SIZE); - - if (c <= 0) - break; - - if (bdp->cbd_sc & BD_SC_READY) { - info->flags |= TX_WAKEUP; - break; - } - - if (from_user) { - if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { - if (!ret) - ret = -EFAULT; - break; - } - } else { - memcpy(__va(bdp->cbd_bufaddr), buf, c); - } - - bdp->cbd_datlen = c; - bdp->cbd_sc |= BD_SC_READY; - - buf += c; - count -= c; - ret += c; - - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - info->tx_cur = (cbd_t *)bdp; - } - return ret; -} - -static int rs_8xx_write_room(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->device, "rs_write_room")) - return 0; - - if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) { - info->flags &= ~TX_WAKEUP; - ret = TX_BUF_SIZE; - } - else { - info->flags |= TX_WAKEUP; - ret = 0; - } - return ret; -} - -/* I could track this with transmit counters....maybe later. -*/ -static int rs_8xx_chars_in_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) - return 0; - return 0; -} - -static void rs_8xx_flush_buffer(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) - return; - - /* There is nothing to "flush", whatever we gave the CPM - * is on its way out. - */ - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - info->flags &= ~TX_WAKEUP; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_8xx_send_xchar(struct tty_struct *tty, char ch) -{ - volatile cbd_t *bdp; - - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_send_char")) - return; - - bdp = info->tx_cur; - while (bdp->cbd_sc & BD_SC_READY); - - *((char *)__va(bdp->cbd_bufaddr)) = ch; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - - /* Get next BD. - */ - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = info->tx_bd_base; - else - bdp++; - - info->tx_cur = (cbd_t *)bdp; -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_8xx_throttle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - rs_8xx_send_xchar(tty, STOP_CHAR(tty)); - -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); -#endif -} - -static void rs_8xx_unthrottle(struct tty_struct * tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_8xx_send_xchar(tty, START_CHAR(tty)); - } -#ifdef modem_control - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -#ifdef maybe -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct async_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - - cli(); - status = serial_in(info, UART_LSR); - sti(); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); -} -#endif - -static int get_modem_info(ser_info_t *info, unsigned int *value) -{ - unsigned int result = 0; -#ifdef modem_control - unsigned char control, status; - - control = info->MCR; - cli(); - status = serial_in(info, UART_MSR); - sti(); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -#endif - return put_user(result,value); -} - -static int set_modem_info(ser_info_t *info, unsigned int cmd, - unsigned int *value) -{ - int error; - unsigned int arg; - - error = get_user(arg, value); - if (error) - return error; -#ifdef modem_control - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - info->MCR |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR |= UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; -#endif - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - break; - case TIOCMSET: - info->MCR = ((info->MCR & ~(UART_MCR_RTS | -#ifdef TIOCM_OUT1 - UART_MCR_OUT1 | - UART_MCR_OUT2 | -#endif - UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) -#ifdef TIOCM_OUT1 - | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) - | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) -#endif - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - break; - default: - return -EINVAL; - } - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); -#endif - return 0; -} - -/* Sending a break is a two step process on the SMC/SCC. It is accomplished - * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT - * command. We take advantage of the begin/end functions to make this - * happen. - */ -static void begin_break(ser_info_t *info) -{ - volatile cpm8260_t *cp; - uint page, sblock; - ushort num; - - cp = cpmp; - - if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) { - if (num == 0) { - page = CPM_CR_SMC1_PAGE; - sblock = CPM_CR_SMC1_SBLOCK; - } - else { - page = CPM_CR_SMC2_PAGE; - sblock = CPM_CR_SMC2_SBLOCK; - } - } - else { - num -= SCC_NUM_BASE; - switch (num) { - case 0: - page = CPM_CR_SCC1_PAGE; - sblock = CPM_CR_SCC1_SBLOCK; - break; - case 1: - page = CPM_CR_SCC2_PAGE; - sblock = CPM_CR_SCC2_SBLOCK; - break; - case 2: - page = CPM_CR_SCC3_PAGE; - sblock = CPM_CR_SCC3_SBLOCK; - break; - case 3: - page = CPM_CR_SCC4_PAGE; - sblock = CPM_CR_SCC4_SBLOCK; - break; - default: return; - } - } - cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_STOP_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); -} - -static void end_break(ser_info_t *info) -{ - volatile cpm8260_t *cp; - uint page, sblock; - ushort num; - - cp = cpmp; - - if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) { - if (num == 0) { - page = CPM_CR_SMC1_PAGE; - sblock = CPM_CR_SMC1_SBLOCK; - } - else { - page = CPM_CR_SMC2_PAGE; - sblock = CPM_CR_SMC2_SBLOCK; - } - } - else { - num -= SCC_NUM_BASE; - switch (num) { - case 0: - page = CPM_CR_SCC1_PAGE; - sblock = CPM_CR_SCC1_SBLOCK; - break; - case 1: - page = CPM_CR_SCC2_PAGE; - sblock = CPM_CR_SCC2_SBLOCK; - break; - case 2: - page = CPM_CR_SCC3_PAGE; - sblock = CPM_CR_SCC3_SBLOCK; - break; - case 3: - page = CPM_CR_SCC4_PAGE; - sblock = CPM_CR_SCC4_SBLOCK; - break; - default: return; - } - } - cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_RESTART_TX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break(ser_info_t *info, int duration) -{ - current->state = TASK_INTERRUPTIBLE; -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); -#endif - begin_break(info); - schedule_timeout(duration); - end_break(info); -#ifdef SERIAL_DEBUG_SEND_BREAK - printk("done jiffies=%lu\n", jiffies); -#endif -} - - -static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int error; - ser_info_t *info = (ser_info_t *)tty->driver_data; - int retval; - struct async_icount cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ - - if (serial_paranoia_check(info, tty->device, "rs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCSBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - begin_break(info); - return 0; - case TIOCCBRK: - retval = tty_check_change(tty); - if (retval) - return retval; - end_break(info); - return 0; - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); - case TIOCSSOFTCAR: - error = get_user(arg, (unsigned int *) arg); - if (error) - return error; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); -#ifdef maybe - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); -#endif - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: -#ifdef modem_control - cli(); - /* note the counters on entry */ - cprev = info->state->icount; - sti(); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cli(); - cnow = info->state->icount; /* atomic copy */ - sti(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ -#else - return 0; -#endif - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - cli(); - cnow = info->state->icount; - sti(); - p_cuser = (struct serial_icounter_struct *) arg; - error = put_user(cnow.cts, &p_cuser->cts); - if (error) return error; - error = put_user(cnow.dsr, &p_cuser->dsr); - if (error) return error; - error = put_user(cnow.rng, &p_cuser->rng); - if (error) return error; - error = put_user(cnow.dcd, &p_cuser->dcd); - if (error) return error; - return 0; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -/* FIX UP modem control here someday...... -*/ -static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - - if ( (tty->termios->c_cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - change_speed(info); - -#ifdef modem_control - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { - info->MCR |= UART_MCR_RTS; - } - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_8xx_start(tty); - } -#endif - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_8xx_close(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct serial_state *state; - unsigned long flags; - int idx; - volatile smc_t *smcp; - volatile scc_t *sccp; - - if (!info || serial_paranoia_check(info, tty->device, "rs_close")) - return; - - state = info->state; - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif - if ((tty->count == 1) && (state->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); - state->count = 0; - } - if (state->count) { - DBG_CNT("before DEC-2"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->read_status_mask &= ~BD_SC_EMPTY; - if (info->flags & ASYNC_INITIALIZED) { - if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { - smcp = &immr->im_smc[idx]; - smcp->smc_smcm &= ~SMCM_RX; - smcp->smc_smcmr &= ~SMCMR_REN; - } - else { - sccp = &immr->im_scc[idx - SCC_IDX_BASE]; - sccp->scc_sccm &= ~UART_SCCM_RX; - sccp->scc_gsmrl &= ~SCC_GSMRL_ENR; - } - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - rs_8xx_wait_until_sent(tty, info->timeout); - } - shutdown(info); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - info->event = 0; - info->tty = 0; - if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; - restore_flags(flags); -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - unsigned long orig_jiffies, char_time; - /*int lsr;*/ - volatile cbd_t *bdp; - - if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) - return; - -#ifdef maybe - if (info->state->type == PORT_UNKNOWN) - return; -#endif - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = 1; - if (timeout) - char_time = MIN(char_time, timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - - /* We go through the loop at least once because we can't tell - * exactly when the last character exits the shifter. There can - * be at least two characters waiting to be sent after the buffers - * are empty. - */ - do { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif - current->state = TASK_INTERRUPTIBLE; -/* current->counter = 0; make us low-priority */ - schedule_timeout(char_time); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - bdp = info->tx_cur; - } while (bdp->cbd_sc & BD_SC_READY); - current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_8xx_hangup(struct tty_struct *tty) -{ - ser_info_t *info = (ser_info_t *)tty->driver_data; - struct serial_state *state = info->state; - - if (serial_paranoia_check(info, tty->device, "rs_hangup")) - return; - - state = info->state; - - rs_8xx_flush_buffer(tty); - shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); - info->tty = 0; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - ser_info_t *info) -{ -#ifdef DO_THIS_LATER - DECLARE_WAITQUEUE(wait, current); -#endif - struct serial_state *state = info->state; - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - * If this is an SMC port, we don't have modem control to wait - * for, so just get out here. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR)) || - (info->state->smc_scc_num < SCC_NUM_BASE)) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; -#ifdef DO_THIS_LATER - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); -#endif - cli(); - if (!tty_hung_up_p(filp)) - state->count--; - sti(); - info->blocked_open++; - while (1) { - cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - sti(); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - state->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif -#endif /* DO_THIS_LATER */ - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, ser_info_t **ret_info) -{ - struct serial_state *sstate; - - sstate = rs_table + line; - if (sstate->info) { - sstate->count++; - *ret_info = (ser_info_t *)sstate->info; - return 0; - } - else { - return -ENOMEM; - } -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_8xx_open(struct tty_struct *tty, struct file * filp) -{ - ser_info_t *info; - int retval, line; - - line = MINOR(tty->device) - tty->driver.minor_start; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - retval = get_async_struct(line, &info); - if (retval) - return retval; - if (serial_paranoia_check(info, tty->device, "rs_open")) - return -ENODEV; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, - info->state->count); -#endif - tty->driver_data = info; - info->tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - MOD_INC_USE_COUNT; - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - - if ((info->state->count == 1) && - (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; - change_speed(info); - } - - info->session = current->session; - info->pgrp = current->pgrp; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttys%d successful...", info->line); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static int inline line_info(char *buf, struct serial_state *state) -{ -#ifdef notdef - struct async_struct *info = state->info, scr_info; - char stat_buf[30], control, status; -#endif - int ret; - - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", - state->line, - (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC", - state->port, state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - -#ifdef notdef - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->port = state->port; - info->flags = state->flags; - info->quot = 0; - info->tty = 0; - } - cli(); - status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); - sti(); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); - - if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); - - if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); - - if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); - - if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); -#endif - return ret; -} - -int rs_8xx_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, &rs_table[i]); - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (begin-off); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); -} - - -/* - * The serial console driver used during boot. Note that these names - * clash with those found in "serial.c", so we currently can't support - * the 16xxx uarts and these at the same time. I will fix this to become - * an indirect function call from tty_io.c (or something). - */ - -#ifdef CONFIG_SERIAL_CONSOLE - -/* - * Print a string to the serial port trying not to disturb any possible - * real use of the port... - */ -static void serial_console_write(struct console *c, const char *s, - unsigned count) -{ - struct serial_state *ser; - ser_info_t *info; - unsigned i; - volatile cbd_t *bdp, *bdbase; - volatile smc_uart_t *up; - volatile u_char *cp; - - ser = rs_table + c->index; - - /* If the port has been initialized for general use, we have - * to use the buffer descriptors allocated there. Otherwise, - * we simply use the single buffer allocated. - */ - if ((info = (ser_info_t *)ser->info) != NULL) { - bdp = info->tx_cur; - bdbase = info->tx_bd_base; - } - else { - /* Pointer to UART in parameter ram. - */ - up = (smc_uart_t *)&immr->im_dprambase[ser->port]; - - /* Get the address of the host memory buffer. - */ - bdp = bdbase = (cbd_t *)&immr->im_dprambase[up->smc_tbase]; - } - - /* - * We need to gracefully shut down the transmitter, disable - * interrupts, then send our bytes out. - */ - - /* - * Now, do each character. This is not as bad as it looks - * since this is a holding FIFO and not a transmitting FIFO. - * We could add the complexity of filling the entire transmit - * buffer, but we would just wait longer between accesses...... - */ - for (i = 0; i < count; i++, s++) { - /* Wait for transmitter fifo to empty. - * Ready indicates output is ready, and xmt is doing - * that, not that it is ready for us to send. - */ - while (bdp->cbd_sc & BD_SC_READY); - /* Send the character out. */ - cp = __va(bdp->cbd_bufaddr); - *cp = *s; - - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - - if (bdp->cbd_sc & BD_SC_WRAP) - bdp = bdbase; - else - bdp++; - - /* if a LF, also do CR... */ - if (*s == 10) { - while (bdp->cbd_sc & BD_SC_READY); - cp = __va(bdp->cbd_bufaddr); - *cp = 13; - bdp->cbd_datlen = 1; - bdp->cbd_sc |= BD_SC_READY; - - if (bdp->cbd_sc & BD_SC_WRAP) { - bdp = bdbase; - } - else { - bdp++; - } - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - while (bdp->cbd_sc & BD_SC_READY); - - if (info) - info->tx_cur = (cbd_t *)bdp; -} - -static kdev_t serial_console_device(struct console *c) -{ - return MKDEV(TTYAUX_MAJOR, 64 + c->index); -} - -/* - * Register console. - */ -long __init console_8xx_init(long kmem_start, long kmem_end) -{ - register_console(&sercons); - return kmem_start; -} - -#endif - -/* Default console baud rate as determined by the board information - * structure. - */ -static int baud_idx; - -/* - * The serial driver boot-time initialization code! - */ -int __init rs_8xx_init(void) -{ - struct serial_state * state; - ser_info_t *info; - uint mem_addr, dp_addr; - int i, j, idx; - uint page, sblock; - volatile cbd_t *bdp; - volatile cpm8260_t *cp; - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile scc_t *scp; - volatile scc_uart_t *sup; - volatile immap_t *immap; - volatile iop8260_t *io; - - init_bh(SERIAL_BH, do_serial_bh); - - show_serial_version(); - - /* Initialize the tty_driver structure */ - - /*memset(&serial_driver, 0, sizeof(struct tty_driver));*/ - __clear_user(&serial_driver,sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver.driver_name = "serial"; -#ifdef CONFIG_DEVFS_FS - serial_driver.name = "tts/%d"; -#else - serial_driver.name = "ttyS"; -#endif - serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - baud_idx | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; - serial_driver.refcount = &serial_refcount; - serial_driver.table = serial_table; - serial_driver.termios = serial_termios; - serial_driver.termios_locked = serial_termios_locked; - - serial_driver.open = rs_8xx_open; - serial_driver.close = rs_8xx_close; - serial_driver.write = rs_8xx_write; - serial_driver.put_char = rs_8xx_put_char; - serial_driver.write_room = rs_8xx_write_room; - serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer; - serial_driver.flush_buffer = rs_8xx_flush_buffer; - serial_driver.ioctl = rs_8xx_ioctl; - serial_driver.throttle = rs_8xx_throttle; - serial_driver.unthrottle = rs_8xx_unthrottle; - serial_driver.send_xchar = rs_8xx_send_xchar; - serial_driver.set_termios = rs_8xx_set_termios; - serial_driver.stop = rs_8xx_stop; - serial_driver.start = rs_8xx_start; - serial_driver.hangup = rs_8xx_hangup; - serial_driver.wait_until_sent = rs_8xx_wait_until_sent; - serial_driver.read_proc = rs_8xx_read_proc; - - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS - callout_driver.name = "cua/%d"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - - if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - - immap = immr; - cp = &immap->im_cpm; - io = &immap->im_ioport; - - /* This should have been done long ago by the early boot code, - * but do it again to make sure. - */ - *(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; - *(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2; - - /* Geeze, here we go....Picking I/O port bits....Lots of - * choices. If you don't like mine, pick your own. - * Configure SMCs Tx/Rx. SMC1 is only on Port D, SMC2 is - * only on Port A. You either pick 'em, or not. - */ - io->iop_ppard |= 0x00c00000; - io->iop_pdird |= 0x00400000; - io->iop_pdird &= ~0x00800000; - io->iop_psord &= ~0x00c00000; -#if USE_SMC2 - io->iop_ppara |= 0x00c00000; - io->iop_pdira |= 0x00400000; - io->iop_pdira &= ~0x00800000; - io->iop_psora &= ~0x00c00000; -#endif - - /* Configure SCC2 and SCC3. Be careful about the fine print. - * Secondary options are only available when you take away - * the primary option. Unless the pins are used for something - * else, SCC2 and SCC3 are on Port B. - * Port B, 8 - SCC3 TxD - * Port B, 12 - SCC2 TxD - * Port B, 14 - SCC3 RxD - * Port B, 15 - SCC2 RxD - */ - io->iop_pparb |= 0x008b0000; - io->iop_pdirb |= 0x00880000; - io->iop_psorb |= 0x00880000; - io->iop_pdirb &= ~0x00030000; - io->iop_psorb &= ~0x00030000; - - /* Wire BRG1 to SMC1 and BRG2 to SMC2. - */ - immap->im_cpmux.cmx_smr = 0; - - /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and - * BRG4 to SCC3. - */ - immap->im_cpmux.cmx_scr &= ~0x00ffff00; - immap->im_cpmux.cmx_scr |= 0x00121b00; - - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->magic = SSTATE_MAGIC; - state->line = i; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; - state->normal_termios = serial_driver.init_termios; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n", - i, state->port, - (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC"); -#ifdef CONFIG_SERIAL_CONSOLE - /* If we just printed the message on the console port, and - * we are about to initialize it for general use, we have - * to wait a couple of character times for the CR/NL to - * make it out of the transmit buffer. - */ - if (i == CONFIG_SERIAL_CONSOLE_PORT) - mdelay(2); -#endif - info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); - if (info) { - /*memset(info, 0, sizeof(ser_info_t));*/ - __clear_user(info,sizeof(ser_info_t)); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - info->magic = SERIAL_MAGIC; - info->flags = state->flags; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - info->tqueue_hangup.routine = do_serial_hangup; - info->tqueue_hangup.data = info; - info->line = i; - info->state = state; - state->info = (struct async_struct *)info; - - /* We need to allocate a transmit and receive buffer - * descriptors from dual port ram, and a character - * buffer area from host mem. - */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); - - /* Allocate space for FIFOs in the host memory. - */ - mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; - info->rx_cur = info->rx_bd_base = (cbd_t *)bdp; - - for (j=0; j<(RX_NUM_FIFO-1); j++) { - bdp->cbd_bufaddr = __pa(mem_addr); - bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; - mem_addr += RX_BUF_SIZE; - bdp++; - } - bdp->cbd_bufaddr = __pa(mem_addr); - bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - - if ((idx = state->smc_scc_num) < SCC_NUM_BASE) { - sp = &immap->im_smc[idx]; - up = (smc_uart_t *)&immap->im_dprambase[state->port]; - up->smc_rbase = dp_addr; - } - else { - scp = &immap->im_scc[idx - SCC_IDX_BASE]; - sup = (scc_uart_t *)&immap->im_dprambase[state->port]; - sup->scc_genscc.scc_rbase = dp_addr; - } - - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); - - /* Allocate space for FIFOs in the host memory. - */ - mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); - - /* Set the physical address of the host memory - * buffers in the buffer descriptors, and the - * virtual address for us to work with. - */ - bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; - info->tx_cur = info->tx_bd_base = (cbd_t *)bdp; - - for (j=0; j<(TX_NUM_FIFO-1); j++) { - bdp->cbd_bufaddr = __pa(mem_addr); - bdp->cbd_sc = BD_SC_INTRPT; - mem_addr += TX_BUF_SIZE; - bdp++; - } - bdp->cbd_bufaddr = __pa(mem_addr); - bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); - - if (idx < SCC_NUM_BASE) { - up->smc_tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; - up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle charater - * time requires some additional tuning. - */ - up->smc_mrblr = 1; - up->smc_maxidl = 0; - up->smc_brkcr = 1; - - /* Send the CPM an initialize command. - */ - if (state->smc_scc_num == 0) { - page = CPM_CR_SMC1_PAGE; - sblock = CPM_CR_SMC1_SBLOCK; - } - else { - page = CPM_CR_SMC2_PAGE; - sblock = CPM_CR_SMC2_SBLOCK; - } - - cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Disable all interrupts and clear all pending - * events. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; - } - else { - sup->scc_genscc.scc_tbase = dp_addr; - - /* Set up the uart parameters in the - * parameter ram. - */ - sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; - sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; - - /* Set this to 1 for now, so we get single - * character interrupts. Using idle charater - * time requires some additional tuning. - */ - sup->scc_genscc.scc_mrblr = 1; - sup->scc_maxidl = 0; - sup->scc_brkcr = 1; - sup->scc_parec = 0; - sup->scc_frmec = 0; - sup->scc_nosec = 0; - sup->scc_brkec = 0; - sup->scc_uaddr1 = 0; - sup->scc_uaddr2 = 0; - sup->scc_toseq = 0; - sup->scc_char1 = 0x8000; - sup->scc_char2 = 0x8000; - sup->scc_char3 = 0x8000; - sup->scc_char4 = 0x8000; - sup->scc_char5 = 0x8000; - sup->scc_char6 = 0x8000; - sup->scc_char7 = 0x8000; - sup->scc_char8 = 0x8000; - sup->scc_rccm = 0xc0ff; - - /* Send the CPM an initialize command. - */ - if (state->smc_scc_num == 2) { - page = CPM_CR_SCC2_PAGE; - sblock = CPM_CR_SCC2_SBLOCK; - } - else { - page = CPM_CR_SCC3_PAGE; - sblock = CPM_CR_SCC3_SBLOCK; - } - - cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - scp->scc_gsmrh = 0; - scp->scc_gsmrl = - (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); - - /* Disable all interrupts and clear all pending - * events. - */ - scp->scc_sccm = 0; - scp->scc_scce = 0xffff; - scp->scc_dsr = 0x7e7e; - scp->scc_pmsr = 0x3000; - } - - /* Install interrupt handler. - */ - request_irq(state->irq, rs_8xx_interrupt, 0, "uart", - info); - - /* Set up the baud rate generator. - */ - m8260_cpm_setbrg(state->smc_scc_num, - baud_table[baud_idx]); - - /* If the port is the console, enable Rx and Tx. - */ -#ifdef CONFIG_SERIAL_CONSOLE - if (i == CONFIG_SERIAL_CONSOLE_PORT) - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; -#endif - } - } - return 0; -} - -/* This must always be called before the rs_8xx_init() function, otherwise - * it blows away the port control information. -*/ -static int __init serial_console_setup(struct console *co, char *options) -{ - struct serial_state *ser; - uint mem_addr, dp_addr, bidx; - volatile cbd_t *bdp; - volatile cpm8260_t *cp; - volatile immap_t *immap; - volatile smc_t *sp; - volatile smc_uart_t *up; - volatile iop8260_t *io; - bd_t *bd; - - bd = (bd_t *)__res; - - for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) - if (bd->bi_baudrate == baud_table[bidx]) - break; - - co->cflag = CREAD|CLOCAL|bidx|CS8; - baud_idx = bidx; - - ser = rs_table + co->index; - - - immap = immr; - cp = &immap->im_cpm; - io = &immap->im_ioport; - - /* This should have been done long ago by the early boot code, - * but do it again to make sure. - */ - *(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; - *(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2; - - /* Right now, assume we are using SMCs. - */ - sp = &immap->im_smc[ser->smc_scc_num]; - - /* When we get here, the CPM has been reset, so we need - * to configure the port. - * We need to allocate a transmit and receive buffer descriptor - * from dual port ram, and a character buffer area from host mem. - */ - up = (smc_uart_t *)&immap->im_dprambase[ser->port]; - - /* Disable transmitter/receiver. - */ - sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); - - /* Use Port D for SMC1 instead of other functions. - */ - io->iop_ppard |= 0x00c00000; - io->iop_pdird |= 0x00400000; - io->iop_pdird &= ~0x00800000; - io->iop_psord &= ~0x00c00000; - - /* Allocate space for two buffer descriptors in the DP ram. - */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2, 8); - - /* Allocate space for two 2 byte FIFOs in the host memory. - */ - mem_addr = m8260_cpm_hostalloc(4, 1); - - /* Set the physical address of the host memory buffers in - * the buffer descriptors. - */ - bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; - bdp->cbd_bufaddr = __pa(mem_addr); - (bdp+1)->cbd_bufaddr = __pa(mem_addr+2); - - /* For the receive, set empty and wrap. - * For transmit, set wrap. - */ - bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; - (bdp+1)->cbd_sc = BD_SC_WRAP; - - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rbase = dp_addr; /* Base of receive buffer desc. */ - up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */ - up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; - up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; - - /* Set this to 1 for now, so we get single character interrupts. - */ - up->smc_mrblr = 1; /* receive buffer length */ - up->smc_maxidl = 0; /* wait forever for next char */ - - /* Send the CPM an initialize command. - */ - cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, - CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); - - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - - /* Set up the baud rate generator. - */ - m8260_cpm_setbrg(ser->smc_scc_num, bd->bi_baudrate); - - /* And finally, enable Rx and Tx. - */ - sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; - - return 0; -} diff -urN linux-2.4.25/arch/ppc/Makefile linux-2.4.26/arch/ppc/Makefile --- linux-2.4.25/arch/ppc/Makefile 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/Makefile 2004-04-14 06:05:27.000000000 -0700 @@ -72,9 +72,9 @@ DRIVERS += arch/ppc/8xx_io/8xx_io.o endif -ifdef CONFIG_8260 -SUBDIRS += arch/ppc/8260_io -DRIVERS += arch/ppc/8260_io/8260_io.o +ifdef CONFIG_CPM2 +SUBDIRS += arch/ppc/cpm2_io +DRIVERS += arch/ppc/cpm2_io/cpm2_io.o endif ifdef CONFIG_APUS diff -urN linux-2.4.25/arch/ppc/boot/common/misc-simple.c linux-2.4.26/arch/ppc/boot/common/misc-simple.c --- linux-2.4.25/arch/ppc/boot/common/misc-simple.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/boot/common/misc-simple.c 2004-04-14 06:05:27.000000000 -0700 @@ -75,7 +75,7 @@ extern void gunzip(void *, int, unsigned char *, int *); extern void serial_fixups(void); -static struct bi_record * +struct bi_record * decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, void *ignored) { diff -urN linux-2.4.25/arch/ppc/boot/simple/embed_config.c linux-2.4.26/arch/ppc/boot/simple/embed_config.c --- linux-2.4.25/arch/ppc/boot/simple/embed_config.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/boot/simple/embed_config.c 2004-04-14 06:05:27.000000000 -0700 @@ -14,7 +14,7 @@ #endif #ifdef CONFIG_8260 #include -#include +#include #endif #ifdef CONFIG_4xx #include @@ -394,10 +394,10 @@ clk_8260(bd_t *bd) { uint scmr, vco_out, clkin; - uint plldf, pllmf, busdf, brgdf, cpmdf; - volatile immap_t *ip; + uint plldf, pllmf, busdf, cpmdf; + volatile cpm2_map_t *ip; - ip = (immap_t *)IMAP_ADDR; + ip = (cpm2_map_t *)CPM_MAP_ADDR; scmr = ip->im_clkrst.car_scmr; /* The clkin is always bus frequency. @@ -502,7 +502,6 @@ embed_config(bd_t **bdp) { u_char *cp, *keyvals; - int i; bd_t *bd; keyvals = (u_char *)*bdp; @@ -582,7 +581,7 @@ */ bd->bi_intfreq = 200000000; } -#endif /* RPX6 for testing */ +#endif /* RPX6 */ #ifdef CONFIG_ADS8260 void diff -urN linux-2.4.25/arch/ppc/boot/simple/m8260_tty.c linux-2.4.26/arch/ppc/boot/simple/m8260_tty.c --- linux-2.4.25/arch/ppc/boot/simple/m8260_tty.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/boot/simple/m8260_tty.c 2004-04-14 06:05:27.000000000 -0700 @@ -3,7 +3,8 @@ */ #include #include -#include +#include +#include uint no_print; extern char *params[]; @@ -29,12 +30,12 @@ volatile scc_uart_t *sup; #endif volatile cbd_t *tbdf, *rbdf; - volatile immap_t *ip; - volatile iop8260_t *io; - volatile cpm8260_t *cp; + volatile cpm2_map_t *ip; + volatile iop_cpm2_t *io; + volatile cpm_cpm2_t *cp; uint dpaddr, memaddr; - ip = (immap_t *)IMAP_ADDR; + ip = (cpm2_map_t *)CPM_MAP_ADDR; cp = &ip->im_cpm; io = &ip->im_ioport; @@ -223,10 +224,10 @@ volatile char *buf; volatile smc_uart_t *up; volatile scc_uart_t *sup; - volatile immap_t *ip; + volatile cpm2_map_t *ip; int i, nc; - ip = (immap_t *)IMAP_ADDR; + ip = (cpm2_map_t *)CPM_MAP_ADDR; #ifdef SCC_CONSOLE sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; @@ -255,10 +256,10 @@ volatile char *buf; volatile smc_uart_t *up; volatile scc_uart_t *sup; - volatile immap_t *ip; + volatile cpm2_map_t *ip; extern bd_t *board_info; - ip = (immap_t *)IMAP_ADDR; + ip = (cpm2_map_t *)CPM_MAP_ADDR; #ifdef SCC_CONSOLE sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase]; @@ -298,9 +299,9 @@ volatile cbd_t *rbdf; volatile smc_uart_t *up; volatile scc_uart_t *sup; - volatile immap_t *ip; + volatile cpm2_map_t *ip; - ip = (immap_t *)IMAP_ADDR; + ip = (cpm2_map_t *)CPM_MAP_ADDR; #ifdef SCC_CONSOLE sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase]; diff -urN linux-2.4.25/arch/ppc/config.in linux-2.4.26/arch/ppc/config.in --- linux-2.4.25/arch/ppc/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/config.in 2004-04-14 06:05:27.000000000 -0700 @@ -57,14 +57,30 @@ if [ "$CONFIG_8260" = "y" ]; then define_bool CONFIG_SERIAL_CONSOLE y - bool 'Support for EST8260' CONFIG_EST8260 + define_bool CONFIG_CPM2 y + bool ' MPC8272 Family Support' CONFIG_8272 + choice 'Machine Type' \ + "ADS8272 CONFIG_ADS8272 \ + EST8260 CONFIG_EST8260 \ + RPX8260 CONFIG_RPX6" RPX8260 +fi + +if [ "$CONFIG_ADS8272" = "y" ]; then + define_bool CONFIG_PQ2ADS y fi if [ "$CONFIG_40x" = "y" ]; then choice 'Machine Type' \ "CPCI405 CONFIG_CPCI405 \ + EP405/EP405PC CONFIG_EP405 \ + Redwood-5 CONFIG_REDWOOD_5 \ + Redwood-6 CONFIG_REDWOOD_6 \ Oak CONFIG_OAK \ Walnut CONFIG_WALNUT" Walnut + + if [ "$CONFIG_EP405" = "y" ]; then + bool 'EP405PC Support' CONFIG_EP405PC + fi fi if [ "$CONFIG_44x" = "y" ]; then @@ -170,11 +186,6 @@ if [ "$CONFIG_4xx" = "y" ]; then - bool 'PPC4xx DMA controller support' CONFIG_PPC4xx_DMA - if [ "$CONFIG_PPC4xx_DMA" = "y" ]; then - define_bool CONFIG_PPC4xx_EDMA y - fi - # # Set generic PPC4xx options # @@ -194,10 +205,18 @@ define_bool CONFIG_405GP y fi + if [ "$CONFIG_EP405" = "y" ]; then + define_bool CONFIG_405GP y + fi + if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" ]; then define_bool CONFIG_403GCX y fi + if [ "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then + define_bool CONFIG_STB03xxx y + fi + if [ "$CONFIG_WALNUT" = "y" ]; then define_bool CONFIG_405GP y fi @@ -213,19 +232,22 @@ # # Set options based on processor implementation # - if [ "$CONFIG_405GP" = "y" ]; then + if [ "$CONFIG_405GP" = "y" -o "$CONFIG_STB03xxx" = "y" ]; then define_bool CONFIG_IBM_OCP y + define_bool CONFIG_PPC_OCP y define_bool CONFIG_405 y fi if [ "$CONFIG_440GP" = "y" ]; then define_bool CONFIG_IBM_OCP y + define_bool CONFIG_PPC_OCP y define_bool CONFIG_GEN550 y define_bool CONFIG_440 y fi if [ "$CONFIG_440GX" = "y" ]; then define_bool CONFIG_IBM_OCP y + define_bool CONFIG_PPC_OCP y define_bool CONFIG_GEN550 y define_bool CONFIG_IBM_EMAC4 y define_bool CONFIG_440A y @@ -248,15 +270,26 @@ define_bool CONFIG_BOOKE y fi + bool 'PPC4xx DMA controller support' CONFIG_PPC4xx_DMA + if [ "$CONFIG_PPC4xx_DMA" = "y" ]; then + if [ "$CONFIG_405GP" = "y" ]; then + define_bool CONFIG_PPC4xx_EDMA y + fi + if [ "$CONFIG_STB03xxx" = "y" ]; then + define_bool CONFIG_STBXXX_DMA y + fi + fi + # # Set other board specific options # if [ "$CONFIG_OAK" = "y" -o "$CONFIG_TIVO" = "y" -o \ - "$CONFIG_WALNUT" = "y" ]; then + "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" -o \ + "$CONFIG_WALNUT" = "y" ]; then define_bool CONFIG_IBM_OPENBIOS y fi - if [ "$CONFIG_WALNUT" = "y" ]; then + if [ "$CONFIG_WALNUT" = "y" -o "$CONFIG_EP405" = "y" ]; then define_bool CONFIG_BIOS_FIXUP y fi @@ -572,8 +605,8 @@ source arch/ppc/8xx_io/Config.in fi -if [ "$CONFIG_8260" = "y" ]; then -source arch/ppc/8260_io/Config.in +if [ "$CONFIG_CPM2" = "y" ]; then +source arch/ppc/cpm2_io/Config.in fi source drivers/usb/Config.in diff -urN linux-2.4.25/arch/ppc/configs/ads8272_defconfig linux-2.4.26/arch/ppc/configs/ads8272_defconfig --- linux-2.4.25/arch/ppc/configs/ads8272_defconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/ads8272_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,629 @@ +# +# Automatically generated by make menuconfig: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_ADVANCED_OPTIONS=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_8260=y +CONFIG_PPC_STD_MMU=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_CPM2=y +CONFIG_8272=y +CONFIG_ADS8272=y +# CONFIG_EST8260 is not set +CONFIG_PQ2ADS=y +# CONFIG_SMP is not set +CONFIG_EMBEDDEDBOOT=y + +# +# General setup +# +# CONFIG_HIGHMEM is not set +# CONFIG_LOWMEM_SIZE_BOOL is not set +# CONFIG_KERNEL_START_BOOL is not set +# CONFIG_TASK_SIZE_BOOL is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +# CONFIG_PCI is not set +# CONFIG_PC_KEYBOARD is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_GEN_RTC is not set +# CONFIG_PPC_RTC is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +# CONFIG_IRDA_ULTRA is not set +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# +# CONFIG_IRTTY_SIR is not set +# CONFIG_IRPORT_SIR is not set +# CONFIG_DONGLE is not set +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_IRCC_FIR is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Input core support +# +CONFIG_INPUT=m +CONFIG_INPUT_KEYBDEV=m +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_UINPUT is not set + +# +# Macintosh device drivers +# + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_CRAMFS=m +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_ROOT_NFS=y +CONFIG_NFSD=m +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_SMB_UNIX is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# 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_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 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_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8260 CPM Options +# +CONFIG_SCC_CONSOLE=y +# CONFIG_SCC_ENET is not set +CONFIG_FEC_ENET=y +CONFIG_FCC1_ENET=y +CONFIG_FCC2_ENET=y +# CONFIG_FCC3_ENET is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/configs/ep405_defconfig linux-2.4.26/arch/ppc/configs/ep405_defconfig --- linux-2.4.25/arch/ppc/configs/ep405_defconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/ep405_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,549 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +# CONFIG_6xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_4xx=y +# CONFIG_CPCI405 is not set +CONFIG_EP405=y +# CONFIG_REDWOOD_5 is not set +# CONFIG_REDWOOD_6 is not set +# CONFIG_OAK is not set +# CONFIG_WALNUT is not set +CONFIG_EP405PC=y +# CONFIG_SMP is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_UART0_TTYS0=y +# CONFIG_UART0_TTYS1 is not set +CONFIG_405GP=y +CONFIG_IBM_OCP=y +CONFIG_PPC_OCP=y +CONFIG_405=y +CONFIG_IBM405_ERR51=y +CONFIG_IBM405_ERR77=y +# CONFIG_PPC4xx_DMA is not set +CONFIG_BIOS_FIXUP=y + +# +# General setup +# +# CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_PCI=y +# CONFIG_PC_KEYBOARD is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +CONFIG_GEN_RTC=y +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_STATS=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# On-chip net devices +# +CONFIG_IBM_OCP_ENET=y +# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set +CONFIG_IBM_OCP_ENET_RX_BUFF=64 +CONFIG_IBM_OCP_ENET_TX_BUFF=8 +CONFIG_IBM_OCP_ENET_GAP=8 +CONFIG_IBM_OCP_ENET_SKB_RES=0 +CONFIG_OCP_NET=y +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set + +# +# Macintosh device drivers +# + +# +# Character devices +# +# CONFIG_VT is not set +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 + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PPC405_ALGO=y +CONFIG_I2C_PPC405_ADAP=y +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_PROC is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/configs/est8260_defconfig linux-2.4.26/arch/ppc/configs/est8260_defconfig --- linux-2.4.25/arch/ppc/configs/est8260_defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/est8260_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -1,5 +1,5 @@ # -# Automatically generated make config: don't edit +# Automatically generated by make menuconfig: don't edit # # CONFIG_UID16 is not set # CONFIG_RWSEM_GENERIC_SPINLOCK is not set @@ -10,6 +10,7 @@ # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set # # Loadable module support @@ -22,13 +23,17 @@ CONFIG_PPC=y CONFIG_PPC32=y CONFIG_6xx=y -# CONFIG_4xx is not set +# CONFIG_40x is not set +# CONFIG_44x is not set # CONFIG_POWER3 is not set # CONFIG_POWER4 is not set # CONFIG_8xx is not set CONFIG_8260=y CONFIG_PPC_STD_MMU=y CONFIG_SERIAL_CONSOLE=y +CONFIG_CPM2=y +# CONFIG_8272 is not set +# CONFIG_ADS8272 is not set CONFIG_EST8260=y # CONFIG_SMP is not set CONFIG_EMBEDDEDBOOT=y @@ -37,11 +42,16 @@ # General setup # # CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 # CONFIG_ISA is not set # CONFIG_EISA is not set # CONFIG_SBUS is not set # CONFIG_MCA is not set # CONFIG_PCI is not set +# CONFIG_PC_KEYBOARD is not set CONFIG_NET=y CONFIG_SYSCTL=y CONFIG_SYSVIPC=y @@ -81,6 +91,7 @@ # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set CONFIG_BLK_DEV_LOOP=y @@ -126,12 +137,14 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q is not set # -# +# SCTP Configuration (EXPERIMENTAL) # +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -280,6 +293,7 @@ # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set # # Macintosh device drivers @@ -310,14 +324,6 @@ # Joysticks # # CONFIG_INPUT_GAMEPORT is not set - -# -# Input core support is needed for gameports -# - -# -# Input core support is needed for joysticks -# # CONFIG_QIC02_TAPE is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_IPMI_PANIC_EVENT is not set @@ -329,6 +335,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_AMD_PM768 is not set # CONFIG_NVRAM is not set @@ -342,6 +349,10 @@ # # CONFIG_FTAPE is not set # CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# # CONFIG_DRM is not set # @@ -353,6 +364,7 @@ # File systems # # CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set @@ -362,6 +374,7 @@ # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BEFS_DEBUG is not set # CONFIG_BFS_FS is not set @@ -403,6 +416,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -411,6 +429,7 @@ # CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set CONFIG_ROOT_NFS=y # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set @@ -466,13 +485,24 @@ # CONFIG_USB is not set # +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# # Bluetooth support # # CONFIG_BLUEZ is not set # +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# # Library routines # +# CONFIG_CRC32 is not set # CONFIG_ZLIB_INFLATE is not set # CONFIG_ZLIB_DEFLATE is not set @@ -480,3 +510,4 @@ # Kernel hacking # # CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/configs/redwood5_defconfig linux-2.4.26/arch/ppc/configs/redwood5_defconfig --- linux-2.4.25/arch/ppc/configs/redwood5_defconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/redwood5_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,573 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +# CONFIG_6xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_4xx=y +# CONFIG_CPCI405 is not set +# CONFIG_EP405 is not set +CONFIG_REDWOOD_5=y +# CONFIG_REDWOOD_6 is not set +# CONFIG_OAK is not set +# CONFIG_WALNUT is not set +# CONFIG_SMP is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_UART0_TTYS0=y +# CONFIG_UART0_TTYS1 is not set +CONFIG_STB03xxx=y +CONFIG_IBM_OCP=y +CONFIG_PPC_OCP=y +CONFIG_405=y +CONFIG_IBM405_ERR51=y +CONFIG_IBM405_ERR77=y +CONFIG_PPC4xx_DMA=y +CONFIG_STBXXX_DMA=y +CONFIG_IBM_OPENBIOS=y + +# +# General setup +# +# CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +# CONFIG_PCI is not set +# CONFIG_PC_KEYBOARD is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +CONFIG_GEN_RTC=y +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_STATS=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDECS is not set +# 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_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +# CONFIG_SMC9194 is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# On-chip net devices +# +# CONFIG_IBM_OCP_ENET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set + +# +# Macintosh device drivers +# + +# +# Character devices +# +# CONFIG_VT is not set +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 + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PPC405_ALGO=y +CONFIG_I2C_PPC405_ADAP=y +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_PROC is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/configs/redwood6_defconfig linux-2.4.26/arch/ppc/configs/redwood6_defconfig --- linux-2.4.25/arch/ppc/configs/redwood6_defconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/redwood6_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,534 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +# CONFIG_6xx is not set +CONFIG_40x=y +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_4xx=y +# CONFIG_CPCI405 is not set +# CONFIG_EP405 is not set +# CONFIG_REDWOOD_5 is not set +CONFIG_REDWOOD_6=y +# CONFIG_OAK is not set +# CONFIG_WALNUT is not set +# CONFIG_SMP is not set +# CONFIG_MATH_EMULATION is not set +CONFIG_NOT_COHERENT_CACHE=y +CONFIG_UART0_TTYS0=y +# CONFIG_UART0_TTYS1 is not set +CONFIG_STB03xxx=y +CONFIG_IBM_OCP=y +CONFIG_PPC_OCP=y +CONFIG_405=y +CONFIG_IBM405_ERR51=y +CONFIG_IBM405_ERR77=y +CONFIG_PPC4xx_DMA=y +CONFIG_STBXXX_DMA=y +CONFIG_IBM_OPENBIOS=y + +# +# General setup +# +# CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +# CONFIG_PCI is not set +# CONFIG_PC_KEYBOARD is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +CONFIG_GEN_RTC=y +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_STATS=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_OAKNET is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRAMCA is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +# CONFIG_SMC9194 is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# On-chip net devices +# +# CONFIG_IBM_OCP_ENET is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set + +# +# Macintosh device drivers +# + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/configs/rpx8260_defconfig linux-2.4.26/arch/ppc/configs/rpx8260_defconfig --- linux-2.4.25/arch/ppc/configs/rpx8260_defconfig 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/configs/rpx8260_defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,535 @@ +# +# Automatically generated make config: don't edit +# +# CONFIG_UID16 is not set +# CONFIG_RWSEM_GENERIC_SPINLOCK is not set +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_HAVE_DEC_LOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Platform support +# +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_E500 is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +CONFIG_8260=y +CONFIG_PPC_STD_MMU=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_CPM2=y +# CONFIG_8272 is not set +# CONFIG_ADS8272 is not set +# CONFIG_EST8260 is not set +CONFIG_RPX6=y +# CONFIG_SMP is not set +CONFIG_EMBEDDEDBOOT=y + +# +# General setup +# +# CONFIG_HIGHMEM is not set +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +# CONFIG_PCI is not set +# CONFIG_PC_KEYBOARD is not set +CONFIG_NET=y +CONFIG_SYSCTL=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_ELF=y +CONFIG_KERNEL_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_GEN_RTC is not set +# CONFIG_PPC_RTC is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_CISS_MONITOR_THREAD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT 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 + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MACE is not set +# CONFIG_BMAC is not set +# CONFIG_GMAC is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_GIANFAR is not set +# CONFIG_GFAR_NAPI is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +# CONFIG_FB is not set + +# +# Input core support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set + +# +# Macintosh device drivers +# + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# MPC8260 CPM Options +# +# CONFIG_SCC_CONSOLE is not set +# CONFIG_SCC_ENET is not set +CONFIG_FEC_ENET=y +# CONFIG_FCC1_ENET is not set +# CONFIG_FCC2_ENET is not set +CONFIG_FCC3_ENET=y + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=0 diff -urN linux-2.4.25/arch/ppc/cpm2_io/Config.in linux-2.4.26/arch/ppc/cpm2_io/Config.in --- linux-2.4.25/arch/ppc/cpm2_io/Config.in 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/Config.in 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,26 @@ +# +# MPC8260 Communication options +# +mainmenu_option next_comment +comment 'MPC8260 CPM Options' +bool 'Enable SCC Console' CONFIG_SCC_CONSOLE +if [ "$CONFIG_NET_ETHERNET" = "y" ]; then + bool 'CPM SCC Ethernet' CONFIG_SCC_ENET + if [ "$CONFIG_SCC_ENET" = "y" ]; then + bool 'Ethernet on SCC1' CONFIG_SCC1_ENET + if [ "$CONFIG_SCC1_ENET" != "y" ]; then + bool 'Ethernet on SCC2' CONFIG_SCC2_ENET + fi + fi +# +# CONFIG_FEC_ENET is only used to get netdevices to call our init +# function. Any combination of FCC1,2,3 are supported. +# + bool 'FCC Ethernet' CONFIG_FEC_ENET + if [ "$CONFIG_FEC_ENET" = "y" ]; then + bool 'Ethernet on FCC1' CONFIG_FCC1_ENET + bool 'Ethernet on FCC2' CONFIG_FCC2_ENET + bool 'Ethernet on FCC3' CONFIG_FCC3_ENET + fi +fi +endmenu diff -urN linux-2.4.25/arch/ppc/cpm2_io/Makefile linux-2.4.26/arch/ppc/cpm2_io/Makefile --- linux-2.4.25/arch/ppc/cpm2_io/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/Makefile 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,17 @@ +# +# Makefile for the linux CPM2 ppc-specific parts of comm processor +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := cpm2_io.o + +obj-y := commproc.o uart.o + +obj-$(CONFIG_FEC_ENET) += fcc_enet.o +obj-$(CONFIG_SCC_ENET) += enet.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.25/arch/ppc/cpm2_io/commproc.c linux-2.4.26/arch/ppc/cpm2_io/commproc.c --- linux-2.4.25/arch/ppc/cpm2_io/commproc.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/commproc.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,179 @@ +/* + * General Purpose functions for the global management of the + * 8260 Communication Processor Module. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com) + * 2.3.99 Updates + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space. The allocator for that is here. When the communication + * process is reset, we reclaim the memory available. There is + * currently no deallocator for this memory. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static uint dp_alloc_base; /* Starting offset in DP ram */ +static uint dp_alloc_top; /* Max offset + 1 */ +static uint host_buffer; /* One page of host buffer */ +static uint host_end; /* end + 1 */ +cpm_cpm2_t *cpmp; /* Pointer to comm processor space */ + +/* We allocate this here because it is used almost exclusively for + * the communication processor devices. + */ +cpm2_map_t *cpm2_immr; + +void +cpm2_reset(void) +{ + volatile cpm2_map_t *imp; + volatile cpm_cpm2_t *commproc; + uint vpgaddr; + + cpm2_immr = imp = (volatile cpm2_map_t *)CPM_MAP_ADDR; + commproc = &imp->im_cpm; + + /* Reclaim the DP memory for our use. + */ + dp_alloc_base = CPM_DATAONLY_BASE; + dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; + + /* Set the host page for allocation. + */ + host_buffer = + (uint) alloc_bootmem_pages(PAGE_SIZE * NUM_CPM_HOST_PAGES); + host_end = host_buffer + (PAGE_SIZE * NUM_CPM_HOST_PAGES); + + vpgaddr = host_buffer; + + /* Tell everyone where the comm processor resides. + */ + cpmp = (cpm_cpm2_t *)commproc; +} + +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. + */ +uint +cpm2_dpalloc(uint size, uint align) +{ + uint retloc; + uint align_mask, off; + uint savebase; + + align_mask = align - 1; + savebase = dp_alloc_base; + + if ((off = (dp_alloc_base & align_mask)) != 0) + dp_alloc_base += (align - off); + + if ((dp_alloc_base + size) >= dp_alloc_top) { + dp_alloc_base = savebase; + return(CPM_DP_NOSPACE); + } + + retloc = dp_alloc_base; + dp_alloc_base += size; + + return(retloc); +} + +/* We also own one page of host buffer space for the allocation of + * UART "fifos" and the like. + */ +uint +cpm2_hostalloc(uint size, uint align) +{ + uint retloc; + uint align_mask, off; + uint savebase; + + align_mask = align - 1; + savebase = host_buffer; + + if ((off = (host_buffer & align_mask)) != 0) + host_buffer += (align - off); + + if ((host_buffer + size) >= host_end) { + host_buffer = savebase; + return(0); + } + + retloc = host_buffer; + host_buffer += size; + + return(retloc); +} + +/* Set a baud rate generator. This needs lots of work. There are + * eight BRGs, which can be connected to the CPM channels or output + * as clocks. The BRGs are in two different block of internal + * memory mapped space. + * The baud rate clock is the system clock divided by something. + * It was set up long ago during the initial boot phase and is + * is given to us. + * Baud rate clocks are zero-based in the driver code (as that maps + * to port numbers). Documentation uses 1-based numbering. + */ +#define BRG_INT_CLK (((bd_t *)__res)->bi_brgfreq) +#define BRG_UART_CLK (BRG_INT_CLK/16) + +/* This function is used by UARTS, or anything else that uses a 16x + * oversampled clock. + */ +void +cpm2_setbrg(uint brg, uint rate) +{ + volatile uint *bp; + + /* This is good enough to get SMCs running..... + */ + if (brg < 4) { + bp = (uint *)&cpm2_immr->im_brgc1; + } + else { + bp = (uint *)&cpm2_immr->im_brgc5; + brg -= 4; + } + bp += brg; + *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN; +} + +/* This function is used to set high speed synchronous baud rate + * clocks. + */ +void +cpm2_fastbrg(uint brg, uint rate, int div16) +{ + volatile uint *bp; + + if (brg < 4) { + bp = (uint *)&cpm2_immr->im_brgc1; + } + else { + bp = (uint *)&cpm2_immr->im_brgc5; + brg -= 4; + } + bp += brg; + *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; + if (div16) + *bp |= CPM_BRG_DIV16; +} diff -urN linux-2.4.25/arch/ppc/cpm2_io/enet.c linux-2.4.26/arch/ppc/cpm2_io/enet.c --- linux-2.4.25/arch/ppc/cpm2_io/enet.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/enet.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,857 @@ +/* + * Ethernet driver for Motorola MPC8260. + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com) + * 2.3.99 Updates + * + * I copied this from the 8xx CPM Ethernet driver, so follow the + * credits back through that. + * + * This version of the driver is somewhat selectable for the different + * processor/board combinations. It works for the boards I know about + * now, and should be easily modified to include others. Some of the + * configuration information is contained in and the + * remainder is here. + * + * Buffer descriptors are kept in the CPM dual port RAM, and the frame + * buffers are in the host memory. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Theory of Operation + * + * The MPC8260 CPM performs the Ethernet processing on an SCC. It can use + * an aribtrary number of buffers on byte boundaries, but must have at + * least two receive buffers to prevent constant overrun conditions. + * + * The buffer descriptors are allocated from the CPM dual port memory + * with the data buffers allocated from host memory, just like all other + * serial communication protocols. The host memory buffers are allocated + * from the free page pool, and then divided into smaller receive and + * transmit buffers. The size of the buffers should be a power of two, + * since that nicely divides the page. This creates a ring buffer + * structure similar to the LANCE and other controllers. + * + * Like the LANCE driver: + * The driver runs as two independent, single-threaded flows of control. One + * is the send-packet routine, which enforces single-threaded use by the + * cep->tx_busy flag. The other thread is the interrupt handler, which is + * single threaded by the hardware and other software. + */ + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +/* The number of Tx and Rx buffers. These are allocated from the page + * pool. The code may assume these are power of two, so it is best + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#define CPM_ENET_RX_PAGES 4 +#define CPM_ENET_RX_FRSIZE 2048 +#define CPM_ENET_RX_FRPPG (PAGE_SIZE / CPM_ENET_RX_FRSIZE) +#define RX_RING_SIZE (CPM_ENET_RX_FRPPG * CPM_ENET_RX_PAGES) +#define TX_RING_SIZE 8 /* Must be power of two */ +#define TX_RING_MOD_MASK 7 /* for this to work */ + +/* The CPM stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct scc_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + scc_t *sccp; + struct net_device_stats stats; + uint tx_free; + spinlock_t lock; +}; + +static int scc_enet_open(struct net_device *dev); +static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int scc_enet_rx(struct net_device *dev); +static void scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int scc_enet_close(struct net_device *dev); +static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); + +/* These will be configurable for the SCC choice. +*/ +#define CPM_ENET_BLOCK CPM_CR_SCC1_SBLOCK +#define CPM_ENET_PAGE CPM_CR_SCC1_PAGE +#define PROFF_ENET PROFF_SCC1 +#define SCC_ENET 0 +#define SIU_INT_ENET SIU_INT_SCC1 + +/* These are both board and SCC dependent.... +*/ +#define PD_ENET_RXD ((uint)0x00000001) +#define PD_ENET_TXD ((uint)0x00000002) +#define PD_ENET_TENA ((uint)0x00000004) +#define PC_ENET_RENA ((uint)0x00020000) +#define PC_ENET_CLSN ((uint)0x00000004) +#define PC_ENET_TXCLK ((uint)0x00000800) +#define PC_ENET_RXCLK ((uint)0x00000400) +#define CMX_CLK_ROUTE ((uint)0x25000000) +#define CMX_CLK_MASK ((uint)0xff000000) + +/* Specific to a board. +*/ +#define PC_EST8260_ENET_LOOPBACK ((uint)0x80000000) +#define PC_EST8260_ENET_SQE ((uint)0x40000000) +#define PC_EST8260_ENET_NOTFD ((uint)0x20000000) + +static int +scc_enet_open(struct net_device *dev) +{ + + /* I should reset the ring buffers here, but I don't yet know + * a simple way to do that. + */ + netif_start_queue(dev); + return 0; /* Always succeed */ +} + +static int +scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + volatile cbd_t *bdp; + + + /* Fill in a Tx ring entry */ + bdp = cep->cur_tx; + +#ifndef final_version + if (!cep->tx_free || (bdp->cbd_sc & BD_ENET_TX_READY)) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since the tx queue should be stopped. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* If the frame is short, tell CPM to pad it. + */ + if (skb->len <= ETH_ZLEN) + bdp->cbd_sc |= BD_ENET_TX_PAD; + else + bdp->cbd_sc &= ~BD_ENET_TX_PAD; + + /* Set buffer length and buffer pointer. + */ + bdp->cbd_datlen = skb->len; + bdp->cbd_bufaddr = __pa(skb->data); + + /* Save skb pointer. + */ + cep->tx_skbuff[cep->skb_cur] = skb; + + cep->stats.tx_bytes += skb->len; + cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + + spin_lock_irq(&cep->lock); + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + if (!--cep->tx_free) + netif_stop_queue(dev); + + cep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&cep->lock); + + return 0; +} + +static void +scc_enet_timeout(struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + cep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + printk(" Ring data dump: cur_tx %p tx_free %d cur_rx %p.\n", + cep->cur_tx, cep->tx_free, + cep->cur_rx); + bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + if (cep->tx_free) + netif_wake_queue(dev); +} + +/* The interrupt handler. + * This is called from the CPM handler, not the MPC core interrupt. + */ +static void +scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile struct scc_enet_private *cep; + volatile cbd_t *bdp; + ushort int_events; + int must_restart; + + cep = (struct scc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->sccp->scc_scce; + cep->sccp->scc_scce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & SCCE_ENET_RXF) + scc_enet_rx(dev_id); + + /* Check for a transmit error. The manual is a little unclear + * about this, so the debug code until I get it figured out. It + * appears that if TXE is set, then TXB is not set. However, + * if carrier sense is lost during frame transmission, the TXE + * bit is set, "and continues the buffer transmission normally." + * I don't know if "normally" implies TXB is set when the buffer + * descriptor is closed.....trial and error :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { + spin_lock(&cep->lock); + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if (cep->tx_free == TX_RING_SIZE) + break; + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->cbd_sc & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + cep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); + cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + /* I don't know if we can be held off from processing these + * interrupts for more than one frame time. I really hope + * not. In such a case, we would now want to check the + * currently available BD (cur_tx) and determine if any + * buffers between the dirty_tx and cur_tx have also been + * sent. We would want to process anything in between that + * does not have BD_ENET_TX_READY set. + */ + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (!cep->tx_free++) { + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + } + + cep->dirty_tx = (cbd_t *)bdp; + } + + if (must_restart) { + volatile cpm_cpm2_t *cp; + + /* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. + */ + + cp = cpmp; + cp->cp_cpcr = + mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, + CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + spin_unlock(&cep->lock); + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & SCCE_ENET_BSY) + cep->stats.rx_dropped++; + + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +scc_enet_rx(struct net_device *dev) +{ + struct scc_enet_private *cep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct scc_enet_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = cep->cur_rx; + +for (;;) { + if (bdp->cbd_sc & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, both + * the first and last indicators should be set. + */ + if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != + (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) + printk("CPM ENET: rcv is not first+last\n"); +#endif + + /* Frame too long or too short. + */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + cep->stats.rx_length_errors++; + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + cep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + cep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + cep->stats.rx_crc_errors++; + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->cbd_sc & BD_ENET_RX_CL) { + cep->stats.rx_frame_errors++; + } + else { + + /* Process the incoming frame. + */ + cep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + cep->stats.rx_bytes += pkt_len; + + /* This does 16 byte alignment, much more than we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len-4); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len-4, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. + */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = cep->rx_bd_base; + else + bdp++; + + } + cep->cur_rx = (cbd_t *)bdp; + + return 0; +} + +static int +scc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + netif_stop_queue(dev); + + return 0; +} + +static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + + return &cep->stats; +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ + +static void set_multicast_list(struct net_device *dev) +{ + struct scc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile scc_enet_t *ep; + int i, j; + cep = (struct scc_enet_private *)dev->priv; + + /* Get pointer to SCC area in parameter RAM. + */ + ep = (scc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->sccp->scc_psmr |= SCC_PSMR_PRO; + } else { + + cep->sccp->scc_psmr &= ~SCC_PSMR_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->sen_gaddr1 = 0xffff; + ep->sen_gaddr2 = 0xffff; + ep->sen_gaddr3 = 0xffff; + ep->sen_gaddr4 = 0xffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->sen_gaddr1 = 0; + ep->sen_gaddr2 = 0; + ep->sen_gaddr3 = 0; + ep->sen_gaddr4 = 0; + + dmi = dev->mc_list; + + for (i=0; imc_count; i++, dmi = dmi->next) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->sen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, + CPM_ENET_BLOCK, 0, + CPM_CR_SET_GADDR) | CPM_CR_FLG; + /* this delay is necessary here -- Cort */ + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } + } +} + +/* Initialize the CPM Ethernet on SCC. + */ +int __init scc_enet_init(void) +{ + struct net_device *dev; + struct scc_enet_private *cep; + int i, j; + unsigned char *eap; + unsigned long mem_addr; + bd_t *bd; + volatile cbd_t *bdp; + volatile cpm_cpm2_t *cp; + volatile scc_t *sccp; + volatile scc_enet_t *ep; + volatile cpm2_map_t *immap; + volatile iop_cpm2_t *io; + + cp = cpmp; /* Get pointer to Communication Processor */ + + immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */ + io = &immap->im_ioport; + + bd = (bd_t *)__res; + + /* Allocate some private information. + */ + cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); + if (cep == NULL) + return -ENOMEM; + + __clear_user(cep,sizeof(*cep)); + spin_lock_init(&cep->lock); + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + + /* Get pointer to SCC area in parameter RAM. + */ + ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]); + + /* And another to the SCC register area. + */ + sccp = (volatile scc_t *)(&immap->im_scc[SCC_ENET]); + cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */ + + /* Disable receive and transmit in case someone left it running. + */ + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Configure port C and D pins for SCC Ethernet. This + * won't work for all SCC possibilities....it will be + * board/port specific. + */ + io->iop_pparc |= + (PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); + io->iop_pdirc &= + ~(PC_ENET_RENA | PC_ENET_CLSN | PC_ENET_TXCLK | PC_ENET_RXCLK); + io->iop_psorc &= + ~(PC_ENET_RENA | PC_ENET_TXCLK | PC_ENET_RXCLK); + io->iop_psorc |= PC_ENET_CLSN; + + io->iop_ppard |= (PD_ENET_RXD | PD_ENET_TXD | PD_ENET_TENA); + io->iop_pdird |= (PD_ENET_TXD | PD_ENET_TENA); + io->iop_pdird &= ~PD_ENET_RXD; + io->iop_psord |= PD_ENET_TXD; + io->iop_psord &= ~(PD_ENET_RXD | PD_ENET_TENA); + + /* Configure Serial Interface clock routing. + * First, clear all SCC bits to zero, then set the ones we want. + */ + immap->im_cpmux.cmx_scr &= ~CMX_CLK_MASK; + immap->im_cpmux.cmx_scr |= CMX_CLK_ROUTE; + + /* Allocate space for the buffer descriptors in the DP ram. + * These are relative offsets in the DP ram address space. + * Initialize base addresses for the buffer descriptors. + */ + i = cpm2_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->sen_genscc.scc_rbase = i; + cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + i = cpm2_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->sen_genscc.scc_tbase = i; + cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->tx_free = TX_RING_SIZE; + cep->cur_rx = cep->rx_bd_base; + + ep->sen_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + ep->sen_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + /* Set maximum bytes per receive buffer. + * This appears to be an Ethernet frame size, not the buffer + * fragment size. It must be a multiple of four. + */ + ep->sen_genscc.scc_mrblr = PKT_MAXBLR_SIZE; + + /* Set CRC preset and mask. + */ + ep->sen_cpres = 0xffffffff; + ep->sen_cmask = 0xdebb20e3; + + ep->sen_crcec = 0; /* CRC Error counter */ + ep->sen_alec = 0; /* alignment error counter */ + ep->sen_disfc = 0; /* discard frame counter */ + + ep->sen_pads = 0x8888; /* Tx short frame pad character */ + ep->sen_retlim = 15; /* Retry limit threshold */ + + ep->sen_maxflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->sen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + ep->sen_maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ + ep->sen_maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ + + /* Clear hash tables. + */ + ep->sen_gaddr1 = 0; + ep->sen_gaddr2 = 0; + ep->sen_gaddr3 = 0; + ep->sen_gaddr4 = 0; + ep->sen_iaddr1 = 0; + ep->sen_iaddr2 = 0; + ep->sen_iaddr3 = 0; + ep->sen_iaddr4 = 0; + + /* Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + */ + eap = (unsigned char *)&(ep->sen_paddrh); + for (i=5; i>=0; i--) + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; + + ep->sen_pper = 0; /* 'cause the book says so */ + ep->sen_taddrl = 0; /* temp address (LSB) */ + ep->sen_taddrm = 0; + ep->sen_taddrh = 0; /* temp address (MSB) */ + + /* Now allocate the host memory pages and initialize the + * buffer descriptors. + */ + bdp = cep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = cep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += CPM_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cpmp->cp_cpcr = mk_cr_cmd(CPM_ENET_PAGE, CPM_ENET_BLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; + + sccp->scc_scce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); + + /* Install our interrupt handler. + */ + request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev); + + /* Set GSMR_H to enable all normal operating modes. + * Set GSMR_L to enable Ethernet to MC68160. + */ + sccp->scc_gsmrh = 0; + sccp->scc_gsmrl = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); + + /* Set sync/delimiters. + */ + sccp->scc_dsr = 0xd555; + + /* Set processing mode. Use Ethernet CRC, catch broadcast, and + * start frame search 22 bit times after RENA. + */ + sccp->scc_psmr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); + + /* It is now OK to enable the Ethernet transmitter. + * Unfortunately, there are board implementation differences here. + */ + io->iop_pparc &= ~(PC_EST8260_ENET_LOOPBACK | + PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); + io->iop_psorc &= ~(PC_EST8260_ENET_LOOPBACK | + PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); + io->iop_pdirc |= (PC_EST8260_ENET_LOOPBACK | + PC_EST8260_ENET_SQE | PC_EST8260_ENET_NOTFD); + io->iop_pdatc &= ~(PC_EST8260_ENET_LOOPBACK | PC_EST8260_ENET_SQE); + io->iop_pdatc |= PC_EST8260_ENET_NOTFD; + + dev->base_addr = (unsigned long)ep; + dev->priv = cep; + + /* The CPM Ethernet specific entries in the device structure. */ + dev->open = scc_enet_open; + dev->hard_start_xmit = scc_enet_start_xmit; + dev->tx_timeout = scc_enet_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = scc_enet_close; + dev->get_stats = scc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + /* And last, enable the transmit and receive processing. + */ + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + printk("%s: SCC ENET Version 0.1, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + return 0; +} + diff -urN linux-2.4.25/arch/ppc/cpm2_io/fcc_enet.c linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c --- linux-2.4.25/arch/ppc/cpm2_io/fcc_enet.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,2007 @@ +/* + * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * This version of the driver is a combination of the 8xx fec and + * 8260 SCC Ethernet drivers. This version has some additional + * configuration options, which should probably be moved out of + * here. This driver currently works for the EST SBC8260, + * SBS Diablo/BCM, Embedded Planet RPX6, TQM8260, and others. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. Since this is a cache coherent processor and CPM, + * I could also preallocate SKB's and use them directly on the interface. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +#ifdef CONFIG_USE_MDIO +/* Forward declarations of some structures to support different PHYs */ + +typedef struct { + uint mii_data; + void (*funct)(uint mii_reg, struct net_device *dev); +} phy_cmd_t; + +typedef struct { + uint id; + char *name; + + const phy_cmd_t *config; + const phy_cmd_t *startup; + const phy_cmd_t *ack_int; + const phy_cmd_t *shutdown; +} phy_info_t; + +/* Register definitions for the PHY. */ + +#define MII_REG_CR 0 /* Control Register */ +#define MII_REG_SR 1 /* Status Register */ +#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ +#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ +#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ +#define MII_REG_ANER 6 /* A-N Expansion Register */ +#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ +#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ + +/* values for phy_status */ + +#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ +#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ +#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ +#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ +#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ +#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ + +#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ +#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ +#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ +#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ +#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ +#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ +#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ +#endif /* CONFIG_USE_MDIO */ + +/* The number of Tx and Rx buffers. These are allocated from the page + * pool. The code may assume these are power of two, so it is best + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#define FCC_ENET_RX_PAGES 16 +#define FCC_ENET_RX_FRSIZE 2048 +#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ + +/* The FCC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 + +/* Maximum input DMA size. Must be a should(?) be a multiple of 4. +*/ +#define PKT_MAXDMA_SIZE 1520 + +/* Maximum input buffer size. Must be a multiple of 32. +*/ +#define PKT_MAXBLR_SIZE 1536 + +static int fcc_enet_open(struct net_device *dev); +static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int fcc_enet_rx(struct net_device *dev); +static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int fcc_enet_close(struct net_device *dev); +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void fcc_restart(struct net_device *dev, int duplex); +static int fcc_enet_set_mac_address(struct net_device *dev, void *addr); + +/* These will be configurable for the FCC choice. + * Multiple ports can be configured. There is little choice among the + * I/O pins to the PHY, except the clocks. We will need some board + * dependent clock selection. + * Why in the hell did I put these inside #ifdef's? I dunno, maybe to + * help show what pins are used for each device. + */ + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL ((uint)0x00000001) +#define PA1_CRS ((uint)0x00000002) +#define PA1_TXER ((uint)0x00000004) +#define PA1_TXEN ((uint)0x00000008) +#define PA1_RXDV ((uint)0x00000010) +#define PA1_RXER ((uint)0x00000020) +#define PA1_TXDAT ((uint)0x00003c00) +#define PA1_RXDAT ((uint)0x0003c000) +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + +/* CLK12 is receive, CLK11 is transmit. These are board specific. +*/ +#ifdef CONFIG_ADS8272 +#define PC_F1RXCLK ((uint)0x00000400) +#define PC_F1TXCLK ((uint)0x00000200) +#define CMX1_CLK_ROUTE ((uint)0x36000000) +#define CMX1_CLK_MASK ((uint)0xff000000) +#else +#define PC_F1RXCLK ((uint)0x00000800) +#define PC_F1TXCLK ((uint)0x00000400) +#define CMX1_CLK_ROUTE ((uint)0x3e000000) +#define CMX1_CLK_MASK ((uint)0xff000000) +#endif + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER ((uint)0x00000001) +#define PB2_RXDV ((uint)0x00000002) +#define PB2_TXEN ((uint)0x00000004) +#define PB2_RXER ((uint)0x00000008) +#define PB2_COL ((uint)0x00000010) +#define PB2_CRS ((uint)0x00000020) +#define PB2_TXDAT ((uint)0x000003c0) +#define PB2_RXDAT ((uint)0x00003c00) +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + +/* CLK13 is receive, CLK14 is transmit. These are board dependent. +*/ +#ifdef CONFIG_ADS8272 +#define PC_F2RXCLK ((uint)0x00004000) +#define PC_F2TXCLK ((uint)0x00008000) +#define CMX2_CLK_ROUTE ((uint)0x00370000) +#define CMX2_CLK_MASK ((uint)0x00ff0000) +#else +#define PC_F2RXCLK ((uint)0x00001000) +#define PC_F2TXCLK ((uint)0x00002000) +#define CMX2_CLK_ROUTE ((uint)0x00250000) +#define CMX2_CLK_MASK ((uint)0x00ff0000) +#endif + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV ((uint)0x00004000) +#define PB3_RXER ((uint)0x00008000) +#define PB3_TXER ((uint)0x00010000) +#define PB3_TXEN ((uint)0x00020000) +#define PB3_COL ((uint)0x00040000) +#define PB3_CRS ((uint)0x00080000) +#define PB3_TXDAT ((uint)0x0f000000) +#define PB3_RXDAT ((uint)0x00f00000) +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 (0) +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) + +/* CLK15 is receive, CLK16 is transmit. These are board dependent. +*/ +#define PC_F3RXCLK ((uint)0x00004000) +#define PC_F3TXCLK ((uint)0x00008000) +#define CMX3_CLK_ROUTE ((uint)0x00003700) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +/* MII status/control serial interface. +*/ +#ifdef CONFIG_TQM8260 +/* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */ +#define PC_MDIO ((uint)0x00000002) +#define PC_MDCK ((uint)0x00000001) +#elif defined(CONFIG_ADS8272) +#define PC_MDIO ((uint)0x00002000) +#define PC_MDCK ((uint)0x00001000) +#else +#define PC_MDIO ((uint)0x00000004) +#define PC_MDCK ((uint)0x00000020) +#endif + +/* A table of information for supporting FCCs. This does two things. + * First, we know how many FCCs we have and they are always externally + * numbered from zero. Second, it holds control register and I/O + * information that could be different among board designs. + */ +typedef struct fcc_info { + uint fc_fccnum; + uint fc_cpmblock; + uint fc_cpmpage; + uint fc_proff; + uint fc_interrupt; + uint fc_trxclocks; + uint fc_clockroute; + uint fc_clockmask; + uint fc_mdio; + uint fc_mdck; +} fcc_info_t; + +static fcc_info_t fcc_ports[] = { +#ifdef CONFIG_FCC1_ENET + { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1, + (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK, +# if defined(CONFIG_TQM8260) || defined (CONFIG_ADS8272) + PC_MDIO, PC_MDCK }, +# else + 0x00000004, 0x00000100 }, +# endif +#endif +#ifdef CONFIG_FCC2_ENET + { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2, + (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK, +# if defined(CONFIG_TQM8260) || defined (CONFIG_ADS8272) + PC_MDIO, PC_MDCK }, +# elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260) + 0x00400000, 0x00200000 }, +# else + 0x00000002, 0x00000080 }, +# endif +#endif +#ifdef CONFIG_FCC3_ENET + { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3, + (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK, +# if defined(CONFIG_TQM8260) || defined (CONFIG_ADS8272) + PC_MDIO, PC_MDCK }, +# else + 0x00000001, 0x00000040 }, +# endif +#endif +}; + +/* The FCC buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct fcc_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + volatile fcc_t *fccp; + volatile fcc_enet_t *ep; + struct net_device_stats stats; + uint tx_full; + spinlock_t lock; + +#ifdef CONFIG_USE_MDIO + uint phy_id; + uint phy_id_done; + uint phy_status; + phy_info_t *phy; + struct tq_struct phy_task; + + uint sequence_done; + + uint phy_addr; +#endif /* CONFIG_USE_MDIO */ + + int link; + int old_link; + int full_duplex; + + fcc_info_t *fip; +}; + +static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile cpm2_map_t *immap); +static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev); +static void init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io, + volatile cpm2_map_t *immap); +static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile cpm2_map_t *immap); + +#ifdef CONFIG_USE_MDIO +static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); +static uint mii_send_receive(fcc_info_t *fip, uint cmd); + +static void fcc_stop(struct net_device *dev); + +/* Make MII read/write commands for the FCC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ + (VAL & 0xffff)) +#define mk_mii_end 0 +#endif /* CONFIG_USE_MDIO */ + + +static int +fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + volatile cbd_t *bdp; + + if (!cep->link) { + /* Link is down or autonegotiation is in progress. */ + return 1; + } + + /* Fill in a Tx ring entry */ + bdp = cep->cur_tx; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since cep->tx_full should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* If the frame is short, tell CPM to pad it. */ + if (skb->len <= ETH_ZLEN) + bdp->cbd_sc |= BD_ENET_TX_PAD; + else + bdp->cbd_sc &= ~BD_ENET_TX_PAD; + + /* Set buffer length and buffer pointer. */ + bdp->cbd_datlen = skb->len; + bdp->cbd_bufaddr = __pa(skb->data); + + /* Save skb pointer. */ + cep->tx_skbuff[cep->skb_cur] = skb; + + cep->stats.tx_bytes += skb->len; + cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + + spin_lock_irq(&cep->lock); + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + +#if 0 + /* Errata says don't do this. */ + cep->fccp->fcc_ftodr = 0x8000; +#endif + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, start at the beginning again. */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + if (bdp->cbd_sc & BD_ENET_TX_READY) { + netif_stop_queue(dev); + cep->tx_full = 1; + } + + cep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&cep->lock); + + return 0; +} + + +static void +fcc_enet_timeout(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + cep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", + cep->cur_tx, cep->tx_full ? " (full)" : "", + cep->cur_rx); + bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + if (!cep->tx_full) + netif_wake_queue(dev); +} + +/* The interrupt handler. */ +static void +fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile struct fcc_enet_private *cep; + volatile cbd_t *bdp; + ushort int_events; + int must_restart; + + cep = (struct fcc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->fccp->fcc_fcce; + cep->fccp->fcc_fcce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & FCC_ENET_RXF) + fcc_enet_rx(dev_id); + + /* Check for a transmit error. The manual is a little unclear + * about this, so the debug code until I get it figured out. It + * appears that if TXE is set, then TXB is not set. However, + * if carrier sense is lost during frame transmission, the TXE + * bit is set, "and continues the buffer transmission normally." + * I don't know if "normally" implies TXB is set when the buffer + * descriptor is closed.....trial and error :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { + spin_lock(&cep->lock); + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->cbd_sc & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + cep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. */ + dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); + cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + /* I don't know if we can be held off from processing these + * interrupts for more than one frame time. I really hope + * not. In such a case, we would now want to check the + * currently available BD (cur_tx) and determine if any + * buffers between the dirty_tx and cur_tx have also been + * sent. We would want to process anything in between that + * does not have BD_ENET_TX_READY set. + */ + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (cep->tx_full) { + cep->tx_full = 0; + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + } + + cep->dirty_tx = (cbd_t *)bdp; + } + + if (must_restart) { + volatile cpm_cpm2_t *cp; + + /* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. Also, To workaround 8260 device erratum + * CPM37, we must disable and then re-enable the transmitter + * following a Late Collision, Underrun, or Retry Limit error. + */ + cep->fccp->fcc_gfmr &= ~FCC_GFMR_ENT; + udelay(10); /* wait a few microseconds just on principle */ + cep->fccp->fcc_gfmr |= FCC_GFMR_ENT; + + cp = cpmp; + cp->cp_cpcr = + mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, + 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + spin_unlock(&cep->lock); + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & FCC_ENET_BSY) { + cep->stats.rx_dropped++; + } + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +fcc_enet_rx(struct net_device *dev) +{ + struct fcc_enet_private *cep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct fcc_enet_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = cep->cur_rx; + +for (;;) { + if (bdp->cbd_sc & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, both + * the first and last indicators should be set. + */ + if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != + (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) + printk("CPM ENET: rcv is not first+last\n"); +#endif + + /* Frame too long or too short. */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + cep->stats.rx_length_errors++; + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + cep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + cep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + cep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CL) /* Late Collision */ + cep->stats.rx_frame_errors++; + + if (!(bdp->cbd_sc & + (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR + | BD_ENET_RX_OV | BD_ENET_RX_CL))) + { + /* Process the incoming frame. */ + cep->stats.rx_packets++; + + /* Remove the FCS from the packet length. */ + pkt_len = bdp->cbd_datlen - 4; + cep->stats.rx_bytes += pkt_len; + + /* This does 16 byte alignment, much more than we need. */ + skb = dev_alloc_skb(pkt_len); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = cep->rx_bd_base; + else + bdp++; + + } + cep->cur_rx = (cbd_t *)bdp; + + return 0; +} + +static int +fcc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. */ + netif_stop_queue(dev); + + return 0; +} + +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + return &cep->stats; +} + +#ifdef CONFIG_USE_MDIO + +/* NOTE: Most of the following comes from the FEC driver for 860. The + * overall structure of MII code has been retained (as it's proved stable + * and well-tested), but actual transfer requests are processed "at once" + * instead of being queued (there's no interrupt-driven MII transfer + * mechanism, one has to toggle the data/clock bits manually). + */ +static int +mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) +{ + struct fcc_enet_private *fep; + int retval, tmp; + + /* Add PHY address to register command. */ + fep = dev->priv; + regval |= fep->phy_addr << 23; + + retval = 0; + + tmp = mii_send_receive(fep->fip, regval); + if (func) + func(tmp, dev); + + return retval; +} + +static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) +{ + int k; + + if(!c) + return; + + for(k = 0; (c+k)->mii_data != mk_mii_end; k++) + mii_queue(dev, (c+k)->mii_data, (c+k)->funct); +} + +static void mii_parse_sr(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + + if (mii_reg & 0x0004) + s |= PHY_STAT_LINK; + if (mii_reg & 0x0010) + s |= PHY_STAT_FAULT; + if (mii_reg & 0x0020) + s |= PHY_STAT_ANC; + + fep->phy_status = s; + fep->link = (s & PHY_STAT_LINK) ? 1 : 0; +} + +static void mii_parse_cr(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + + if (mii_reg & 0x1000) + s |= PHY_CONF_ANE; + if (mii_reg & 0x4000) + s |= PHY_CONF_LOOP; + + fep->phy_status = s; +} + +static void mii_parse_anar(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_CONF_SPMASK); + + if (mii_reg & 0x0020) + s |= PHY_CONF_10HDX; + if (mii_reg & 0x0040) + s |= PHY_CONF_10FDX; + if (mii_reg & 0x0080) + s |= PHY_CONF_100HDX; + if (mii_reg & 0x00100) + s |= PHY_CONF_100FDX; + + fep->phy_status = s; +} +/* ------------------------------------------------------------------------- */ +/* The Level one LXT970 is used by many boards */ + +#ifdef CONFIG_FCC_LXT970 + +#define MII_LXT970_MIRROR 16 /* Mirror register */ +#define MII_LXT970_IER 17 /* Interrupt Enable Register */ +#define MII_LXT970_ISR 18 /* Interrupt Status Register */ +#define MII_LXT970_CONFIG 19 /* Configuration Register */ +#define MII_LXT970_CSR 20 /* Chip Status Register */ + +static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_STAT_SPMASK); + + if (mii_reg & 0x0800) { + if (mii_reg & 0x1000) + s |= PHY_STAT_100FDX; + else + s |= PHY_STAT_100HDX; + } else { + if (mii_reg & 0x1000) + s |= PHY_STAT_10FDX; + else + s |= PHY_STAT_10HDX; + } + + fep->phy_status = s; +} + +static phy_info_t phy_info_lxt970 = { + 0x07810000, + "LXT970", + + (const phy_cmd_t []) { /* config */ +#if 0 +// { mk_mii_write(MII_REG_ANAR, 0x0021), NULL }, + + /* Set default operation of 100-TX....for some reason + * some of these bits are set on power up, which is wrong. + */ + { mk_mii_write(MII_LXT970_CONFIG, 0), NULL }, +#endif + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* read SR and ISR to acknowledge */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT970_ISR), NULL }, + + /* find out the current status */ + + { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +#endif /* CONFIG_FEC_LXT970 */ + +/* ------------------------------------------------------------------------- */ +/* The Level one LXT971 is used on some of my custom boards */ + +#ifdef CONFIG_FCC_LXT971 + +/* register definitions for the 971 */ + +#define MII_LXT971_PCR 16 /* Port Control Register */ +#define MII_LXT971_SR2 17 /* Status Register 2 */ +#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +#define MII_LXT971_ISR 19 /* Interrupt Status Register */ +#define MII_LXT971_LCR 20 /* LED Control Register */ +#define MII_LXT971_TCR 30 /* Transmit Control Register */ + +/* + * I had some nice ideas of running the MDIO faster... + * The 971 should support 8MHz and I tried it, but things acted really + * weird, so 2.5 MHz ought to be enough for anyone... + */ + +static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_STAT_SPMASK); + + if (mii_reg & 0x4000) { + if (mii_reg & 0x0200) + s |= PHY_STAT_100FDX; + else + s |= PHY_STAT_100HDX; + } else { + if (mii_reg & 0x0200) + s |= PHY_STAT_10FDX; + else + s |= PHY_STAT_10HDX; + } + if (mii_reg & 0x0008) + s |= PHY_STAT_FAULT; + + fep->phy_status = s; +} + +static phy_info_t phy_info_lxt971 = { + 0x0001378e, + "LXT971", + + (const phy_cmd_t []) { /* config */ +// { mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10 Mbps, HD */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + + /* Somehow does the 971 tell me that the link is down + * the first read after power-up. + * read here to get a valid value in ack_int */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* find out the current status */ + + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, + + /* we only need to read ISR to acknowledge */ + + { mk_mii_read(MII_LXT971_ISR), NULL }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +#endif /* CONFIG_FEC_LXT970 */ + + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +#ifdef CONFIG_FCC_QS6612 + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_STAT_SPMASK); + + switch((mii_reg >> 2) & 7) { + case 1: s |= PHY_STAT_10HDX; break; + case 2: s |= PHY_STAT_100HDX; break; + case 5: s |= PHY_STAT_10FDX; break; + case 6: s |= PHY_STAT_100FDX; break; + } + + fep->phy_status = s; +} + +static phy_info_t phy_info_qs6612 = { + 0x00181440, + "QS6612", + + (const phy_cmd_t []) { /* config */ +// { mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 Mbps */ + + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + */ + + { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, + + /* parse cr and anar to get some info */ + + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + + /* we need to read ISR, SR and ANER to acknowledge */ + + { mk_mii_read(MII_QS6612_ISR), NULL }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_ANER), NULL }, + + /* read pcr to get info */ + + { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + + +#endif /* CONFIG_FEC_QS6612 */ + + +/* ------------------------------------------------------------------------- */ +/* The Davicom DM9131 is used on the HYMOD board */ + +#ifdef CONFIG_FCC_DM9131 + +/* register definitions */ + +#define MII_DM9131_ACR 16 /* Aux. Config Register */ +#define MII_DM9131_ACSR 17 /* Aux. Config/Status Register */ +#define MII_DM9131_10TCSR 18 /* 10BaseT Config/Status Reg. */ +#define MII_DM9131_INTR 21 /* Interrupt Register */ +#define MII_DM9131_RECR 22 /* Receive Error Counter Reg. */ +#define MII_DM9131_DISCR 23 /* Disconnect Counter Register */ + +static void mii_parse_dm9131_acsr(uint mii_reg, struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + s &= ~(PHY_STAT_SPMASK); + + switch ((mii_reg >> 12) & 0xf) { + case 1: s |= PHY_STAT_10HDX; break; + case 2: s |= PHY_STAT_10FDX; break; + case 4: s |= PHY_STAT_100HDX; break; + case 8: s |= PHY_STAT_100FDX; break; + } + + fep->phy_status = s; +} + +static phy_info_t phy_info_dm9131 = { + 0x00181b80, + "DM9131", + + (const phy_cmd_t []) { /* config */ + /* parse cr and anar to get some info */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_DM9131_INTR, 0x0002), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + + /* we need to read INTR, SR and ANER to acknowledge */ + + { mk_mii_read(MII_DM9131_INTR), NULL }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_ANER), NULL }, + + /* read acsr to get info */ + + { mk_mii_read(MII_DM9131_ACSR), mii_parse_dm9131_acsr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_DM9131_INTR, 0x0f00), NULL }, + { mk_mii_end, } + }, +}; + + +#endif /* CONFIG_FEC_DM9131 */ + + +static phy_info_t *phy_info[] = { + +#ifdef CONFIG_FCC_LXT970 + &phy_info_lxt970, +#endif /* CONFIG_FEC_LXT970 */ + +#ifdef CONFIG_FCC_LXT971 + &phy_info_lxt971, +#endif /* CONFIG_FEC_LXT971 */ + +#ifdef CONFIG_FCC_QS6612 + &phy_info_qs6612, +#endif /* CONFIG_FEC_QS6612 */ + +#ifdef CONFIG_FCC_DM9131 + &phy_info_dm9131, +#endif /* CONFIG_FEC_DM9131 */ + + NULL +}; + +static void mii_display_status(struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + if (!fep->link && !fep->old_link) { + /* Link is still down - don't print anything */ + return; + } + + printk("%s: status: ", dev->name); + + if (!fep->link) { + printk("link down"); + } else { + printk("link up"); + + switch(s & PHY_STAT_SPMASK) { + case PHY_STAT_100FDX: printk(", 100 Mbps Full Duplex"); break; + case PHY_STAT_100HDX: printk(", 100 Mbps Half Duplex"); break; + case PHY_STAT_10FDX: printk(", 10 Mbps Full Duplex"); break; + case PHY_STAT_10HDX: printk(", 10 Mbps Half Duplex"); break; + default: + printk(", Unknown speed/duplex"); + } + + if (s & PHY_STAT_ANC) + printk(", auto-negotiation complete"); + } + + if (s & PHY_STAT_FAULT) + printk(", remote fault"); + + printk(".\n"); +} + +static void mii_display_config(struct net_device *dev) +{ + volatile struct fcc_enet_private *fep = dev->priv; + uint s = fep->phy_status; + + printk("%s: config: auto-negotiation ", dev->name); + + if (s & PHY_CONF_ANE) + printk("on"); + else + printk("off"); + + if (s & PHY_CONF_100FDX) + printk(", 100FDX"); + if (s & PHY_CONF_100HDX) + printk(", 100HDX"); + if (s & PHY_CONF_10FDX) + printk(", 10FDX"); + if (s & PHY_CONF_10HDX) + printk(", 10HDX"); + if (!(s & PHY_CONF_SPMASK)) + printk(", No speed/duplex selected?"); + + if (s & PHY_CONF_LOOP) + printk(", loopback enabled"); + + printk(".\n"); + + fep->sequence_done = 1; +} + +static void mii_relink(struct net_device *dev) +{ + struct fcc_enet_private *fep = dev->priv; + int duplex; + + fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; + mii_display_status(dev); + fep->old_link = fep->link; + + if (fep->link) { + duplex = 0; + if (fep->phy_status + & (PHY_STAT_100FDX | PHY_STAT_10FDX)) + duplex = 1; + fcc_restart(dev, duplex); + } else { + fcc_stop(dev); + } +} + +static void mii_queue_relink(uint mii_reg, struct net_device *dev) +{ + struct fcc_enet_private *fep = dev->priv; + + fep->phy_task.routine = (void *)mii_relink; + fep->phy_task.data = dev; + schedule_task(&fep->phy_task); +} + +static void mii_queue_config(uint mii_reg, struct net_device *dev) +{ + struct fcc_enet_private *fep = dev->priv; + + fep->phy_task.routine = (void *)mii_display_config; + fep->phy_task.data = dev; + schedule_task(&fep->phy_task); +} + + + +phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } }; +phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } }; + + +/* Read remainder of PHY ID. +*/ +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + struct fcc_enet_private *fep; + int i; + + fep = dev->priv; + fep->phy_id |= (mii_reg & 0xffff); + + for(i = 0; phy_info[i]; i++) + if(phy_info[i]->id == (fep->phy_id >> 4)) + break; + + if(!phy_info[i]) + panic("%s: PHY id 0x%08x is not supported!\n", + dev->name, fep->phy_id); + + fep->phy = phy_info[i]; + + printk("%s: Phy @ 0x%x, type %s (0x%08x)\n", + dev->name, fep->phy_addr, fep->phy->name, fep->phy_id); +} + +/* Scan all of the MII PHY addresses looking for someone to respond + * with a valid ID. This usually happens quickly. + */ +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + struct fcc_enet_private *fep; + uint phytype; + + fep = dev->priv; + + if ((phytype = (mii_reg & 0xfff)) != 0xfff) { + + /* Got first part of ID, now get remainder. */ + fep->phy_id = phytype << 16; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3); + } else { + fep->phy_addr++; + if (fep->phy_addr < 32) { + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), + mii_discover_phy); + } else { + printk("fec: No PHY device found.\n"); + } + } +} + +/* This interrupt occurs when the PHY detects a link change. */ +static void +mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct fcc_enet_private *fep = dev->priv; + + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ +} + +#endif /* CONFIG_USE_MDIO */ + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ +static void +set_multicast_list(struct net_device *dev) +{ + struct fcc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile fcc_enet_t *ep; + int i, j; + + cep = (struct fcc_enet_private *)dev->priv; + +return; + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; + } else { + + cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fen_gaddrh = 0xffffffff; + ep->fen_gaddrl = 0xffffffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + + dmi = dev->mc_list; + + for (i=0; imc_count; i++, dmi = dmi->next) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->fen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, + cep->fip->fc_cpmblock, 0x0c, + CPM_CR_SET_GADDR) | CPM_CR_FLG; + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } + } +} + + +/* Set the individual MAC address. + */ +int fcc_enet_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr= (struct sockaddr *) p; + struct fcc_enet_private *cep; + volatile fcc_enet_t *ep; + unsigned char *eap; + int i; + + cep = (struct fcc_enet_private *)(dev->priv); + ep = cep->ep; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + eap = (unsigned char *) &(ep->fen_paddrh); + for (i=5; i>=0; i--) + *eap++ = addr->sa_data[i]; + + return 0; +} + + +/* Initialize the CPM Ethernet on FCC. + */ +int __init fec_enet_init(void) +{ + struct net_device *dev; + struct fcc_enet_private *cep; + fcc_info_t *fip; + int i, np; + volatile cpm2_map_t *immap; + volatile iop_cpm2_t *io; + + immap = (cpm2_map_t *)CPM_MAP_ADDR; /* and to internal registers */ + io = &immap->im_ioport; + + np = sizeof(fcc_ports) / sizeof(fcc_info_t); + fip = fcc_ports; + + while (np-- > 0) { + + /* Allocate some private information. + */ + cep = (struct fcc_enet_private *) + kmalloc(sizeof(*cep), GFP_KERNEL); + if (cep == NULL) + return -ENOMEM; + + __clear_user(cep,sizeof(*cep)); + spin_lock_init(&cep->lock); + cep->fip = fip; + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + dev->priv = cep; + + init_fcc_shutdown(fip, cep, immap); + init_fcc_ioports(fip, io, immap); + init_fcc_param(fip, dev, immap); + + dev->base_addr = (unsigned long)(cep->ep); + + /* The CPM Ethernet specific entries in the device + * structure. + */ + dev->open = fcc_enet_open; + dev->hard_start_xmit = fcc_enet_start_xmit; + dev->tx_timeout = fcc_enet_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fcc_enet_close; + dev->get_stats = fcc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->set_mac_address = fcc_enet_set_mac_address; + + init_fcc_startup(fip, dev); + + printk("%s: FCC ENET Version 0.3, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + +#ifdef CONFIG_USE_MDIO + /* Queue up command to detect the PHY and initialize the + * remainder of the interface. + */ + cep->phy_addr = 0; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); +#endif /* CONFIG_USE_MDIO */ + + fip++; + } + + return 0; +} + +/* Make sure the device is shut down during initialization. +*/ +static void __init +init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile cpm2_map_t *immap) +{ + volatile fcc_enet_t *ep; + volatile fcc_t *fccp; + + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); + + /* And another to the FCC register area. + */ + fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); + cep->fccp = fccp; /* Keep the pointers handy */ + cep->ep = ep; + + /* Disable receive and transmit in case someone left it running. + */ + fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* Initialize the I/O pins for the FCC Ethernet. +*/ +static void __init +init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io, + volatile cpm2_map_t *immap) +{ + + /* FCC1 pins are on port A/C. FCC2/3 are port B/C. + */ + if (fip->fc_proff == PROFF_FCC1) { + /* Configure port A and C pins for FCC1 Ethernet. + */ + io->iop_pdira &= ~PA1_DIRA0; + io->iop_pdira |= PA1_DIRA1; + io->iop_psora &= ~PA1_PSORA0; + io->iop_psora |= PA1_PSORA1; + io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1); + } + if (fip->fc_proff == PROFF_FCC2) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB2_DIRB0; + io->iop_pdirb |= PB2_DIRB1; + io->iop_psorb &= ~PB2_PSORB0; + io->iop_psorb |= PB2_PSORB1; + io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1); + } + if (fip->fc_proff == PROFF_FCC3) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB3_DIRB0; + io->iop_pdirb |= PB3_DIRB1; + io->iop_psorb &= ~PB3_PSORB0; + io->iop_psorb |= PB3_PSORB1; + io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1); + } + + /* Port C has clocks...... + */ + io->iop_psorc &= ~(fip->fc_trxclocks); + io->iop_pdirc &= ~(fip->fc_trxclocks); + io->iop_pparc |= fip->fc_trxclocks; + +#ifdef CONFIG_USE_MDIO + /* ....and the MII serial clock/data. + */ + io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_podrc &= ~(fip->fc_mdio | fip->fc_mdck); + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck); +#endif /* CONFIG_USE_MDIO */ + + /* Configure Serial Interface clock routing. + * First, clear all FCC bits to zero, + * then set the ones we want. + */ + immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); + immap->im_cpmux.cmx_fcr |= fip->fc_clockroute; +} + +static void __init +init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile cpm2_map_t *immap) +{ + unsigned char *eap; + unsigned long mem_addr; + bd_t *bd; + int i, j; + struct fcc_enet_private *cep; + volatile fcc_enet_t *ep; + volatile cbd_t *bdp; + volatile cpm_cpm2_t *cp; + + cep = (struct fcc_enet_private *)(dev->priv); + ep = cep->ep; + cp = cpmp; + + bd = (bd_t *)__res; + + /* Zero the whole thing.....I must have missed some individually. + * It works when I do this. + */ + memset((char *)ep, 0, sizeof(fcc_enet_t)); + + /* Allocate space for the buffer descriptors in the DP ram. + * These are relative offsets in the DP ram address space. + * Initialize base addresses for the buffer descriptors. + */ +#if 0 + /* I really want to do this, but for some reason it doesn't + * work with the data cache enabled, so I allocate from the + * main memory instead. + */ + i = cpm2_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i]; + cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + i = cpm2_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i]; + cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; +#else + cep->rx_bd_base = (cbd_t *)cpm2_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); + cep->tx_bd_base = (cbd_t *)cpm2_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); +#endif + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->cur_rx = cep->rx_bd_base; + + ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); + ep->fen_genfcc.fcc_riptr = mem_addr; + ep->fen_genfcc.fcc_tiptr = mem_addr+32; + ep->fen_padptr = mem_addr+64; + memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); + + ep->fen_genfcc.fcc_rbptr = 0; + ep->fen_genfcc.fcc_tbptr = 0; + ep->fen_genfcc.fcc_rcrc = 0; + ep->fen_genfcc.fcc_tcrc = 0; + ep->fen_genfcc.fcc_res1 = 0; + ep->fen_genfcc.fcc_res2 = 0; + + ep->fen_camptr = 0; /* CAM isn't used in this driver */ + + /* Set CRC preset and mask. + */ + ep->fen_cmask = 0xdebb20e3; + ep->fen_cpres = 0xffffffff; + + ep->fen_crcec = 0; /* CRC Error counter */ + ep->fen_alec = 0; /* alignment error counter */ + ep->fen_disfc = 0; /* discard frame counter */ + ep->fen_retlim = 15; /* Retry limit threshold */ + ep->fen_pper = 0; /* Normal persistence */ + + /* Clear hash filter tables. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + ep->fen_iaddrh = 0; + ep->fen_iaddrl = 0; + + /* Clear the Out-of-sequence TxBD. + */ + ep->fen_tfcstat = 0; + ep->fen_tfclen = 0; + ep->fen_tfcptr = 0; + + ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + /* Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + * So, far we have only been given one Ethernet address. We make + * it unique by toggling selected bits in the upper byte of the + * non-static part of the address (for the second and third ports, + * the first port uses the address supplied as is). + */ + eap = (unsigned char *)&(ep->fen_paddrh); + for (i=5; i>=0; i--) { + +/* + * The EP8260 only uses FCC3, so we can safely give it the real + * MAC address. + */ +#ifndef CONFIG_RPX6 + if (i == 3 && fip->fc_fccnum != 0) { + dev->dev_addr[i] = bd->bi_enetaddr[i]; + dev->dev_addr[i] ^= (1 << (7 - fip->fc_fccnum)); + *eap++ = dev->dev_addr[i]; + } + else { + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; + } +#else + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; +#endif + } + + ep->fen_taddrh = 0; + ep->fen_taddrm = 0; + ep->fen_taddrl = 0; + + ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ + ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON. + */ + ep->fen_octc = 0; + ep->fen_colc = 0; + ep->fen_broc = 0; + ep->fen_mulc = 0; + ep->fen_uspc = 0; + ep->fen_frgc = 0; + ep->fen_ospc = 0; + ep->fen_jbrc = 0; + ep->fen_p64c = 0; + ep->fen_p65c = 0; + ep->fen_p128c = 0; + ep->fen_p256c = 0; + ep->fen_p512c = 0; + ep->fen_p1024c = 0; + + ep->fen_rfthr = 0; /* Suggested by manual */ + ep->fen_rfcnt = 0; + ep->fen_cftype = 0; + + /* Now allocate the host memory pages and initialize the + * buffer descriptors. + */ + bdp = cep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = cep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FCC_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; +} + +/* Let 'er rip. +*/ +static void __init +init_fcc_startup(fcc_info_t *fip, struct net_device *dev) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *cep; + + cep = (struct fcc_enet_private *)(dev->priv); + fccp = cep->fccp; + + fccp->fcc_fcce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Install our interrupt handler. + */ + if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet", + dev) < 0) + printk("Can't get FCC IRQ %d\n", fip->fc_interrupt); + +#ifdef CONFIG_USE_MDIO + if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, + "mii", dev) < 0) + printk("Can't get MII IRQ %d\n", fip->fc_interrupt); +#endif /* CONFIG_USE_MDIO */ + + /* Set GFMR to enable Ethernet operating mode. + */ + fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* Set sync/delimiters. + */ + fccp->fcc_fdsr = 0xd555; + + /* Set protocol specific processing mode for Ethernet. + * This has to be adjusted for Full Duplex operation after we can + * determine how to detect that. + */ + fccp->fcc_fpsmr = FCC_PSMR_ENCRC; + +#ifdef CONFIG_PQ2ADS + /* Enable the PHY. + */ + *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN; + *(volatile uint *)(BCSR_ADDR + 4) |= BCSR1_FETH_RST; +#endif + +#if defined(CONFIG_USE_MDIO) || defined(CONFIG_TQM8260) + /* start in full duplex mode, and negotiate speed + */ + fcc_restart (dev, 1); +#else + /* start in half duplex mode + */ + fcc_restart (dev, 0); +#endif +} + +#ifdef CONFIG_USE_MDIO +/* MII command/status interface. + * I'm not going to describe all of the details. You can find the + * protocol definition in many other places, including the data sheet + * of most PHY parts. + * I wonder what "they" were thinking (maybe weren't) when they leave + * the I2C in the CPM but I have to toggle these bits...... + */ + +#define FCC_PDATC_MDIO(bit) \ + if (bit) \ + io->iop_pdatc |= fip->fc_mdio; \ + else \ + io->iop_pdatc &= ~fip->fc_mdio; + +#define FCC_PDATC_MDC(bit) \ + if (bit) \ + io->iop_pdatc |= fip->fc_mdck; \ + else \ + io->iop_pdatc &= ~fip->fc_mdck; + +static uint +mii_send_receive(fcc_info_t *fip, uint cmd) +{ + uint retval; + int read_op, i, off; + volatile cpm2_map_t *immap; + volatile iop_cpm2_t *io; + + immap = (cpm2_map_t *)CPM_MAP_ADDR; + io = &immap->im_ioport; + + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + + read_op = ((cmd & 0xf0000000) == 0x60000000); + + /* Write preamble + */ + for (i = 0; i < 32; i++) + { + FCC_PDATC_MDC(0); + FCC_PDATC_MDIO(1); + udelay(1); + FCC_PDATC_MDC(1); + udelay(1); + } + + /* Write data + */ + for (i = 0, off = 31; i < (read_op ? 14 : 32); i++, --off) + { + FCC_PDATC_MDC(0); + FCC_PDATC_MDIO((cmd >> off) & 0x00000001); + udelay(1); + FCC_PDATC_MDC(1); + udelay(1); + } + + retval = cmd; + + if (read_op) + { + retval >>= 16; + + FCC_PDATC_MDC(0); + io->iop_pdirc &= ~fip->fc_mdio; + udelay(1); + FCC_PDATC_MDC(1); + udelay(1); + FCC_PDATC_MDC(0); + udelay(1); + + for (i = 0, off = 15; i < 16; i++, off--) + { + FCC_PDATC_MDC(1); + retval <<= 1; + if (io->iop_pdatc & fip->fc_mdio) + retval++; + udelay(1); + FCC_PDATC_MDC(0); + udelay(1); + } + } + + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + + for (i = 0; i < 32; i++) + { + FCC_PDATC_MDC(0); + FCC_PDATC_MDIO(1); + udelay(1); + FCC_PDATC_MDC(1); + udelay(1); + } + + return retval; +} + +static void +fcc_stop(struct net_device *dev) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *fcp; + + fcp = (struct fcc_enet_private *)(dev->priv); + fccp = fcp->fccp; + + /* Disable transmit/receive */ + fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); +} +#endif /* CONFIG_USE_MDIO */ + +static void +fcc_restart(struct net_device *dev, int duplex) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *fcp; + + fcp = (struct fcc_enet_private *)(dev->priv); + fccp = fcp->fccp; + + if (duplex) + fccp->fcc_fpsmr |= FCC_PSMR_FDE; + else + fccp->fcc_fpsmr &= ~FCC_PSMR_FDE; + + /* Enable transmit/receive */ + fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT; +} + +static int +fcc_enet_open(struct net_device *dev) +{ + struct fcc_enet_private *fep = dev->priv; + +#ifdef CONFIG_USE_MDIO + fep->sequence_done = 0; + fep->link = 0; + + if (fep->phy) { + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, fep->phy->config); + mii_do_cmd(dev, phy_cmd_config); /* display configuration */ + while(!fep->sequence_done) + schedule(); + + mii_do_cmd(dev, fep->phy->startup); + netif_start_queue(dev); + return 0; /* Success */ + } + return -ENODEV; /* No PHY we understand */ +#else + fep->link = 1; + netif_start_queue(dev); + return 0; /* Always succeed */ +#endif /* CONFIG_USE_MDIO */ +} + diff -urN linux-2.4.25/arch/ppc/cpm2_io/uart.c linux-2.4.26/arch/ppc/cpm2_io/uart.c --- linux-2.4.25/arch/ppc/cpm2_io/uart.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/cpm2_io/uart.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,3160 @@ +/* + * UART driver for MPC8260 CPM SCC or SMC + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com) + * 2.3.99 updates + * + * I used the 8xx uart.c driver as the framework for this driver. + * The original code was written for the EST8260 board. I tried to make + * it generic, but there may be some assumptions in the structures that + * have to be fixed later. + * + * The 8xx and 8260 are similar, but not identical. Over time we + * could probably merge these two drivers. + * To save porting time, I did not bother to change any object names + * that are not accessed outside of this file. + * It still needs lots of work........When it was easy, I included code + * to support the SCCs. + * Only the SCCs support modem control, so that is not complete either. + * + * This module exports the following rs232 io functions: + * + * int rs_8xx_init(void); + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAGIC_SYSRQ +#include +#endif + +#ifdef CONFIG_SERIAL_CONSOLE +#include + +/* SCC Console configuration. Not quite finished. The SCC_CONSOLE + * should be the number of the SCC to use, but only SCC1 will + * work at this time. + */ +#ifdef CONFIG_SCC_CONSOLE +#define SCC_CONSOLE 1 +#endif + +/* this defines the index into rs_table for the port to use +*/ +#ifndef CONFIG_SERIAL_CONSOLE_PORT +#define CONFIG_SERIAL_CONSOLE_PORT 0 +#endif +#endif +#define CONFIG_SERIAL_CONSOLE_PORT 0 + +#define TX_WAKEUP ASYNC_SHARE_IRQ + +static char *serial_name = "CPM UART driver"; +static char *serial_version = "0.01"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; +static int serial_console_setup(struct console *co, char *options); + +static void serial_console_write(struct console *c, const char *s, + unsigned count); +static kdev_t serial_console_device(struct console *c); + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +static unsigned long break_pressed; /* break, really ... */ +#endif + +/* + * Serial driver configuration section. Here are the various options: + */ +#define SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + +#define _INLINE_ inline + +#define DBG_CNT(s) + +/* We overload some of the items in the data structure to meet our + * needs. For example, the port address is the CPM parameter ram + * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and + * 2 SMCs. The "hub6" field is used to indicate the channel number, with + * 0 and 1 indicating the SMCs and 2, 3, 4, and 5 are the SCCs. + * Since these ports are so versatile, I don't yet have a strategy for + * their management. For example, SCC1 is used for Ethernet. Right + * now, just don't put them in the table. Of course, right now I just + * want the SMC to work as a uart :-).. + * The "type" field is currently set to 0, for PORT_UNKNOWN. It is + * not currently used. I should probably use it to indicate the port + * type of CMS or SCC. + * The SMCs do not support any modem control signals. + */ +#define smc_scc_num hub6 + +/* The choice of serial port to use for KGDB. If the system has + * two ports, you can use one for console and one for KGDB (which + * doesn't make sense to me, but people asked for it). + */ +#ifdef CONFIG_KGDB_TTYS1 +#define KGDB_SER_IDX 1 /* SCC2/SMC2 */ +#else +#define KGDB_SER_IDX 0 /* SCC1/SMC1 */ +#endif + +#ifndef SCC_CONSOLE + +/* SMC2 is sometimes used for low performance TDM interfaces. Define + * this as 1 if you want SMC2 as a serial port UART managed by this driver. + * Define this as 0 if you wish to use SMC2 for something else. + */ +#define USE_SMC2 1 + +/* Define SCC to ttySx mapping. +*/ +#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */ + +/* Define which SCC is the first one to use for a serial port. These + * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used + * for Ethernet, and the first available SCC for serial UART is SCC2. + * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and + * interrupt vectors in the table below to match. + */ +#define SCC_IDX_BASE 1 /* table index */ + +static struct serial_state rs_table[] = { + /* UART CLK PORT IRQ FLAGS NUM */ + { 0, 0, PROFF_SMC1, SIU_INT_SMC1, 0, 0 }, /* SMC1 ttyS0 */ +#if USE_SMC2 + { 0, 0, PROFF_SMC2, SIU_INT_SMC2, 0, 1 }, /* SMC2 ttyS1 */ +#endif +#ifndef CONFIG_SCC1_ENET + { 0, 0, PROFF_SCC1, SIU_INT_SCC1, 0, SCC_NUM_BASE}, /* SCC1 ttyS2 */ +#endif +#ifndef CONFIG_SCC2_ENET + { 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE + 1}, /* SCC2 ttyS3 */ +#endif +}; + +#else /* SCC_CONSOLE */ +#define SCC_NUM_BASE 0 /* SCC base tty "number" */ +#define SCC_IDX_BASE 0 /* table index */ +static struct serial_state rs_table[] = { + /* UART CLK PORT IRQ FLAGS NUM */ + { 0, 0, PROFF_SCC1, SIU_INT_SCC1, 0, SCC_NUM_BASE}, /* SCC1 ttyS2 */ + { 0, 0, PROFF_SCC2, SIU_INT_SCC2, 0, SCC_NUM_BASE + 1}, /* SCC2 ttyS3 */ +}; +#endif /* SCC_CONSOLE */ + +#define PORT_NUM(P) (((P) < (SCC_NUM_BASE)) ? (P) : (P)-(SCC_NUM_BASE)) + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +/* The number of buffer descriptors and their sizes. +*/ +#define RX_NUM_FIFO 4 +#define RX_BUF_SIZE 32 +#define TX_NUM_FIFO 4 +#define TX_BUF_SIZE 32 + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* The async_struct in serial.h does not really give us what we + * need, so define our own here. + */ +typedef struct serial_info { + int magic; + int flags; + struct serial_state *state; + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int line; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + /* CPM Buffer Descriptor pointers. + */ + cbd_t *rx_bd_base; + cbd_t *rx_cur; + cbd_t *tx_bd_base; + cbd_t *tx_cur; +} ser_info_t; + +static struct console sercons = { + name: "ttyS", + write: serial_console_write, + device: serial_console_device, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: CONFIG_SERIAL_CONSOLE_PORT, +}; + + +static void change_speed(ser_info_t *info); +static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout); + +static inline int serial_paranoia_check(ser_info_t *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null async_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor speeds and the timeouts, + * indexed by the termio value. The generic CPM functions are responsible + * for setting and assigning baud rate generators for us. + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; + + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_8xx_stop(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int idx; + unsigned long flags; + volatile scc_t *sccp; + volatile smc_t *smcp; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + smcp->smc_smcm &= ~SMCM_TX; + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + sccp->scc_sccm &= ~UART_SCCM_TX; + } + restore_flags(flags); +} + +static void rs_8xx_start(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int idx; + unsigned long flags; + volatile scc_t *sccp; + volatile smc_t *smcp; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + smcp->smc_smcm |= SMCM_TX; + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + sccp->scc_sccm |= UART_SCCM_TX; + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void rs_sched_event(ser_info_t *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static _INLINE_ void receive_chars(ser_info_t *info, struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, *cp; + /*int ignored = 0;*/ + int i; + ushort status; + struct async_icount *icount; + volatile cbd_t *bdp; + + icount = &info->state->icount; + + /* Just loop through the closed BDs and copy the characters into + * the buffer. + */ + bdp = info->rx_cur; + for (;;) { + if (bdp->cbd_sc & BD_SC_EMPTY) /* If this one is empty */ + break; /* we are all done */ + + /* The read status mask tell us what we should do with + * incoming characters, especially if errors occur. + * One special case is the use of BD_SC_EMPTY. If + * this is not set, we are supposed to be ignoring + * inputs. In this case, just mark the buffer empty and + * continue. + if (!(info->read_status_mask & BD_SC_EMPTY)) { + bdp->cbd_sc |= BD_SC_EMPTY; + bdp->cbd_sc &= + ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); + + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = info->rx_bd_base; + else + bdp++; + continue; + } + */ + + /* Get the number of characters and the buffer pointer. + */ + i = bdp->cbd_datlen; + cp = (unsigned char *)__va(bdp->cbd_bufaddr); + status = bdp->cbd_sc; +#ifdef CONFIG_KGDB + if (info->state->smc_scc_num == KGDB_SER_IDX && + (*cp == 0x03 || *cp == '$')) { + breakpoint(); + return; + } +#endif + + /* Check to see if there is room in the tty buffer for + * the characters in our BD buffer. If not, we exit + * now, leaving the BD with the characters. We'll pick + * them up again on the next receive interrupt (which could + * be a timeout). + */ + if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) + break; + + while (i-- > 0) { + ch = *cp++; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (status & (BD_SC_BR | BD_SC_FR | + BD_SC_PR | BD_SC_OV)) { + /* + * For statistics only + */ + if (status & BD_SC_BR) + icount->brk++; + else if (status & BD_SC_PR) + icount->parity++; + else if (status & BD_SC_FR) + icount->frame++; + if (status & BD_SC_OV) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + if (status & info->ignore_status_mask) { + if (++ignored > 100) + break; + continue; + } + */ + status &= info->read_status_mask; + + if (status & (BD_SC_BR)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (status & BD_SC_PR) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (status & BD_SC_FR) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (status & BD_SC_OV) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = + TTY_OVERRUN; + } + } + } + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (break_pressed && info->line == sercons.index) { + if (ch != 0 && time_before(jiffies, + break_pressed + HZ*5)) { + handle_sysrq(ch, regs, NULL, NULL); + break_pressed = 0; + goto ignore_char; + } else + break_pressed = 0; + } +#endif + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + ignore_char: +#endif + + /* This BD is ready to be used again. Clear status. + * Get next BD. + */ + bdp->cbd_sc |= BD_SC_EMPTY; + bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); + + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = info->rx_bd_base; + else + bdp++; + } + + info->rx_cur = (cbd_t *)bdp; + + queue_task(&tty->flip.tqueue, &tq_timer); +} + +static _INLINE_ void receive_break(ser_info_t *info, struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + + info->state->icount.brk++; + +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + if (info->line == sercons.index) { + if (!break_pressed) { + break_pressed = jiffies; + return; + } else + break_pressed = 0; + } +#endif + + /* Check to see if there is room in the tty buffer for + * the break. If not, we exit now, losing the break. FIXME + */ + if ((tty->flip.count + 1) >= TTY_FLIPBUF_SIZE) + return; + *(tty->flip.flag_buf_ptr++) = TTY_BREAK; + *(tty->flip.char_buf_ptr++) = 0; + tty->flip.count++; + + queue_task(&tty->flip.tqueue, &tq_timer); +} + + +static _INLINE_ void transmit_chars(ser_info_t *info, struct pt_regs *regs) +{ + + if (info->flags & TX_WAKEUP) { + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + } + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif +} + +#ifdef notdef + /* I need to do this for the SCCs, so it is left as a reminder. + */ +static _INLINE_ void check_modem_status(struct async_struct *info) +{ + int status; + struct async_icount *icount; + + status = serial_in(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->state->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & UART_MSR_DCD)) + hardpps(); +#endif + } + if (status & UART_MSR_DCTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("scheduling hangup..."); +#endif + MOD_INC_USE_COUNT; + if (schedule_task(&info->tqueue_hangup) == 0) + MOD_DEC_USE_COUNT; + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + } + } +} +#endif + +/* + * This is the serial driver's interrupt routine for a single port + */ +static void rs_8xx_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + u_char events; + int idx; + ser_info_t *info; + volatile smc_t *smcp; + volatile scc_t *sccp; + + info = (ser_info_t *)dev_id; + + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + events = smcp->smc_smce; + if (events & SMCM_BRKE) + receive_break(info, regs); + if (events & SMCM_RX) + receive_chars(info, regs); + if (events & SMCM_TX) + transmit_chars(info, regs); + smcp->smc_smce = events; + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + events = sccp->scc_scce; + if (events & SMCM_BRKE) + receive_break(info, regs); + if (events & SCCM_RX) + receive_chars(info, regs); + if (events & SCCM_TX) + transmit_chars(info, regs); + sccp->scc_scce = events; + } + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt_single(%d, %x)...", + info->state->smc_scc_num, events); +#endif +#ifdef modem_control + check_modem_status(info); +#endif + info->last_active = jiffies; +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + ser_info_t *info = (ser_info_t *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (tty) + tty_hangup(tty); + MOD_DEC_USE_COUNT; +} + +/*static void rs_8xx_timer(void) +{ + printk("rs_8xx_timer\n"); +}*/ + + +static int startup(ser_info_t *info) +{ + unsigned long flags; + int retval=0; + int idx; + struct serial_state *state= info->state; + volatile smc_t *smcp; + volatile scc_t *sccp; + volatile smc_uart_t *up; + volatile scc_uart_t *scup; + + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + goto errout; + } + +#ifdef maybe + if (!state->port || !state->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + goto errout; + } +#endif + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, state->irq); +#endif + + +#ifdef modem_control + info->MCR = 0; + if (info->tty->termios->c_cflag & CBAUD) + info->MCR = UART_MCR_DTR | UART_MCR_RTS; +#endif + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + /* + * and set the speed of the serial port + */ + change_speed(info); + + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + + /* Enable interrupts and I/O. + */ + smcp->smc_smcm |= (SMCM_RX | SMCM_TX); + smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN); + + /* We can tune the buffer length and idle characters + * to take advantage of the entire incoming buffer size. + * If mrblr is something other than 1, maxidl has to be + * non-zero or we never get an interrupt. The maxidl + * is the number of character times we wait after reception + * of the last character before we decide no more characters + * are coming. + */ + up = (smc_uart_t *)&cpm2_immr->im_dprambase[state->port]; +#if 0 + up->smc_mrblr = 1; /* receive buffer length */ + up->smc_maxidl = 0; /* wait forever for next char */ +#else + up->smc_mrblr = RX_BUF_SIZE; + up->smc_maxidl = RX_BUF_SIZE; +#endif + up->smc_brkcr = 1; /* number of break chars */ + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + scup = (scc_uart_t *)&cpm2_immr->im_dprambase[state->port]; +#if 0 + scup->scc_genscc.scc_mrblr = 1; /* receive buffer length */ + scup->scc_maxidl = 0; /* wait forever for next char */ +#else + scup->scc_genscc.scc_mrblr = RX_BUF_SIZE; + scup->scc_maxidl = RX_BUF_SIZE; +#endif + + sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + } + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(ser_info_t * info) +{ + unsigned long flags; + struct serial_state *state; + int idx; + volatile smc_t *smcp; + volatile scc_t *sccp; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + state = info->state; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + state->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + + /* Disable interrupts and I/O. + */ + smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); +#ifdef CONFIG_SERIAL_CONSOLE + /* We can't disable the transmitter if this is the + * system console. + */ + if (idx != CONFIG_SERIAL_CONSOLE_PORT) +#endif + smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); +#ifdef CONFIG_SERIAL_CONSOLE + if (idx != CONFIG_SERIAL_CONSOLE_PORT) + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(ser_info_t *info) +{ + int baud_rate; + unsigned cflag, cval, scval, prev_mode; + int i, bits, sbits, idx; + unsigned long flags; + volatile smc_t *smcp; + volatile scc_t *sccp; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + + /* Character length programmed into the mode register is the + * sum of: 1 start bit, number of data bits, 0 or 1 parity bit, + * 1 or 2 stop bits, minus 1. + * The value 'bits' counts this for us. + */ + cval = 0; + scval = 0; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: bits = 5; break; + case CS6: bits = 6; break; + case CS7: bits = 7; break; + case CS8: bits = 8; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: bits = 8; break; + } + sbits = bits - 5; + + if (cflag & CSTOPB) { + cval |= SMCMR_SL; /* Two stops */ + scval |= SCU_PSMR_SL; + bits++; + } + if (cflag & PARENB) { + cval |= SMCMR_PEN; + scval |= SCU_PSMR_PEN; + bits++; + } + if (!(cflag & PARODD)) { + cval |= SMCMR_PM_EVEN; + scval |= (SCU_PSMR_REVP | SCU_PSMR_TEVP); + } + + /* Determine divisor based on baud rate */ + i = cflag & CBAUD; + if (i >= (sizeof(baud_table)/sizeof(int))) + baud_rate = 9600; + else + baud_rate = baud_table[i]; + + info->timeout = (TX_BUF_SIZE*HZ*bits); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + +#ifdef modem_control + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + serial_out(info, UART_IER, info->IER); +#endif + + /* + * Set up parity check flag + */ +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); + if (I_INPCK(info->tty)) + info->read_status_mask |= BD_SC_FR | BD_SC_PR; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= BD_SC_BR; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= BD_SC_PR | BD_SC_FR; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= BD_SC_BR; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= BD_SC_OV; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + info->read_status_mask &= ~BD_SC_EMPTY; + save_flags(flags); cli(); + + /* Start bit has not been added (so don't, because we would just + * subtract it later), and we need to add one for the number of + * stops bits (there is always at least one). + */ + bits++; + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + + /* Set the mode register. We want to keep a copy of the + * enables, because we want to put them back if they were + * present. + */ + prev_mode = smcp->smc_smcmr & (SMCMR_REN | SMCMR_TEN); + smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART + | prev_mode; + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + sccp->scc_psmr = (sbits << 12) | scval; + } + + cpm2_setbrg(info->state->smc_scc_num, baud_rate); + + restore_flags(flags); +} + +static void rs_8xx_put_char(struct tty_struct *tty, unsigned char ch) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + volatile cbd_t *bdp; + + if (serial_paranoia_check(info, tty->device, "rs_put_char")) + return; + + if (!tty) + return; + + bdp = info->tx_cur; + while (bdp->cbd_sc & BD_SC_READY); + + *((char *)__va(bdp->cbd_bufaddr)) = ch; + bdp->cbd_datlen = 1; + bdp->cbd_sc |= BD_SC_READY; + + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + + info->tx_cur = (cbd_t *)bdp; + +} + +static int rs_8xx_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + ser_info_t *info = (ser_info_t *)tty->driver_data; + volatile cbd_t *bdp; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty) + return 0; + + bdp = info->tx_cur; + + while (1) { + c = MIN(count, TX_BUF_SIZE); + + if (c <= 0) + break; + + if (bdp->cbd_sc & BD_SC_READY) { + info->flags |= TX_WAKEUP; + break; + } + + if (from_user) { + if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { + if (!ret) + ret = -EFAULT; + break; + } + } else { + memcpy(__va(bdp->cbd_bufaddr), buf, c); + } + + bdp->cbd_datlen = c; + bdp->cbd_sc |= BD_SC_READY; + + buf += c; + count -= c; + ret += c; + + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + info->tx_cur = (cbd_t *)bdp; + } + return ret; +} + +static int rs_8xx_write_room(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + + if ((info->tx_cur->cbd_sc & BD_SC_READY) == 0) { + info->flags &= ~TX_WAKEUP; + ret = TX_BUF_SIZE; + } + else { + info->flags |= TX_WAKEUP; + ret = 0; + } + return ret; +} + +/* I could track this with transmit counters....maybe later. +*/ +static int rs_8xx_chars_in_buffer(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return 0; +} + +static void rs_8xx_flush_buffer(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + + /* There is nothing to "flush", whatever we gave the CPM + * is on its way out. + */ + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + info->flags &= ~TX_WAKEUP; +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_8xx_send_xchar(struct tty_struct *tty, char ch) +{ + volatile cbd_t *bdp; + + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_send_char")) + return; + + bdp = info->tx_cur; + while (bdp->cbd_sc & BD_SC_READY); + + *((char *)__va(bdp->cbd_bufaddr)) = ch; + bdp->cbd_datlen = 1; + bdp->cbd_sc |= BD_SC_READY; + + /* Get next BD. + */ + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = info->tx_bd_base; + else + bdp++; + + info->tx_cur = (cbd_t *)bdp; +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_8xx_throttle(struct tty_struct * tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + rs_8xx_send_xchar(tty, STOP_CHAR(tty)); + +#ifdef modem_control + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +#endif +} + +static void rs_8xx_unthrottle(struct tty_struct * tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_8xx_send_xchar(tty, START_CHAR(tty)); + } +#ifdef modem_control + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= UART_MCR_RTS; + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +#ifdef maybe +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct async_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + + cli(); + status = serial_in(info, UART_LSR); + sti(); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + return put_user(result,value); +} +#endif + +static int get_modem_info(ser_info_t *info, unsigned int *value) +{ + unsigned int result = 0; +#ifdef modem_control + unsigned char control, status; + + control = info->MCR; + cli(); + status = serial_in(info, UART_MSR); + sti(); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +#ifdef TIOCM_OUT1 + | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) + | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) +#endif + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); +#endif + return put_user(result,value); +} + +static int set_modem_info(ser_info_t *info, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + + error = get_user(arg, value); + if (error) + return error; +#ifdef modem_control + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR |= UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR |= UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR |= UART_MCR_OUT2; +#endif + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR &= ~UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR &= ~UART_MCR_OUT2; +#endif + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | +#ifdef TIOCM_OUT1 + UART_MCR_OUT1 | + UART_MCR_OUT2 | +#endif + UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) +#ifdef TIOCM_OUT1 + | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) + | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) +#endif + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +#endif + return 0; +} + +/* Sending a break is a two step process on the SMC/SCC. It is accomplished + * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT + * command. We take advantage of the begin/end functions to make this + * happen. + */ +static void begin_break(ser_info_t *info) +{ + volatile cpm_cpm2_t *cp; + uint page, sblock; + ushort num; + + cp = cpmp; + + if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) { + if (num == 0) { + page = CPM_CR_SMC1_PAGE; + sblock = CPM_CR_SMC1_SBLOCK; + } + else { + page = CPM_CR_SMC2_PAGE; + sblock = CPM_CR_SMC2_SBLOCK; + } + } + else { + num -= SCC_NUM_BASE; + switch (num) { + case 0: + page = CPM_CR_SCC1_PAGE; + sblock = CPM_CR_SCC1_SBLOCK; + break; + case 1: + page = CPM_CR_SCC2_PAGE; + sblock = CPM_CR_SCC2_SBLOCK; + break; + case 2: + page = CPM_CR_SCC3_PAGE; + sblock = CPM_CR_SCC3_SBLOCK; + break; + case 3: + page = CPM_CR_SCC4_PAGE; + sblock = CPM_CR_SCC4_SBLOCK; + break; + default: return; + } + } + cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_STOP_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); +} + +static void end_break(ser_info_t *info) +{ + volatile cpm_cpm2_t *cp; + uint page, sblock; + ushort num; + + cp = cpmp; + + if ((num = info->state->smc_scc_num) < SCC_NUM_BASE) { + if (num == 0) { + page = CPM_CR_SMC1_PAGE; + sblock = CPM_CR_SMC1_SBLOCK; + } + else { + page = CPM_CR_SMC2_PAGE; + sblock = CPM_CR_SMC2_SBLOCK; + } + } + else { + num -= SCC_NUM_BASE; + switch (num) { + case 0: + page = CPM_CR_SCC1_PAGE; + sblock = CPM_CR_SCC1_SBLOCK; + break; + case 1: + page = CPM_CR_SCC2_PAGE; + sblock = CPM_CR_SCC2_SBLOCK; + break; + case 2: + page = CPM_CR_SCC3_PAGE; + sblock = CPM_CR_SCC3_SBLOCK; + break; + case 3: + page = CPM_CR_SCC4_PAGE; + sblock = CPM_CR_SCC4_SBLOCK; + break; + default: return; + } + } + cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break(ser_info_t *info, int duration) +{ + current->state = TASK_INTERRUPTIBLE; +#ifdef SERIAL_DEBUG_SEND_BREAK + printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); +#endif + begin_break(info); + schedule_timeout(duration); + end_break(info); +#ifdef SERIAL_DEBUG_SEND_BREAK + printk("done jiffies=%lu\n", jiffies); +#endif +} + + +static int rs_8xx_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + ser_info_t *info = (ser_info_t *)tty->driver_data; + int retval; + struct async_icount cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, HZ/4); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*(HZ/10) : HZ/4); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCSBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + begin_break(info); + return 0; + case TIOCCBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + end_break(info); + return 0; + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); + case TIOCSSOFTCAR: + error = get_user(arg, (unsigned int *) arg); + if (error) + return error; + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); +#ifdef maybe + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); +#endif + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: +#ifdef modem_control + cli(); + /* note the counters on entry */ + cprev = info->state->icount; + sti(); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + cli(); + cnow = info->state->icount; /* atomic copy */ + sti(); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ +#else + return 0; +#endif + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + cli(); + cnow = info->state->icount; + sti(); + p_cuser = (struct serial_icounter_struct *) arg; + error = put_user(cnow.cts, &p_cuser->cts); + if (error) return error; + error = put_user(cnow.dsr, &p_cuser->dsr); + if (error) return error; + error = put_user(cnow.rng, &p_cuser->rng); + if (error) return error; + error = put_user(cnow.dcd, &p_cuser->dcd); + if (error) return error; + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* FIX UP modem control here someday...... +*/ +static void rs_8xx_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + + if ( (tty->termios->c_cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info); + +#ifdef modem_control + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(tty->termios->c_cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (tty->termios->c_cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!tty->hw_stopped || + !(tty->termios->c_cflag & CRTSCTS)) { + info->MCR |= UART_MCR_RTS; + } + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_8xx_start(tty); + } +#endif + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_8xx_close(struct tty_struct *tty, struct file * filp) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + int idx; + volatile smc_t *smcp; + volatile scc_t *sccp; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + state = info->state; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, state->count); + state->count = 0; + } + if (state->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->read_status_mask &= ~BD_SC_EMPTY; + if (info->flags & ASYNC_INITIALIZED) { + if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { + smcp = &cpm2_immr->im_smc[idx]; + smcp->smc_smcm &= ~SMCM_RX; + smcp->smc_smcmr &= ~SMCMR_REN; + } + else { + sccp = &cpm2_immr->im_scc[idx - SCC_IDX_BASE]; + sccp->scc_sccm &= ~UART_SCCM_RX; + sccp->scc_gsmrl &= ~SCC_GSMRL_ENR; + } + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + rs_8xx_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + unsigned long orig_jiffies, char_time; + /*int lsr;*/ + volatile cbd_t *bdp; + + if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) + return; + +#ifdef maybe + if (info->state->type == PORT_UNKNOWN) + return; +#endif + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + + /* We go through the loop at least once because we can't tell + * exactly when the last character exits the shifter. There can + * be at least two characters waiting to be sent after the buffers + * are empty. + */ + do { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; +/* current->counter = 0; make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + bdp = info->tx_cur; + } while (bdp->cbd_sc & BD_SC_READY); + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_8xx_hangup(struct tty_struct *tty) +{ + ser_info_t *info = (ser_info_t *)tty->driver_data; + struct serial_state *state = info->state; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + state = info->state; + + rs_8xx_flush_buffer(tty); + shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + ser_info_t *info) +{ +#ifdef DO_THIS_LATER + DECLARE_WAITQUEUE(wait, current); +#endif + struct serial_state *state = info->state; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + * If this is an SMC port, we don't have modem control to wait + * for, so just get out here. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR)) || + (info->state->smc_scc_num < SCC_NUM_BASE)) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; +#ifdef DO_THIS_LATER + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + state->line, state->count); +#endif + cli(); + if (!tty_hung_up_p(filp)) + state->count--; + sti(); + info->blocked_open++; + while (1) { + cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + sti(); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + state->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, state->count); +#endif +#endif /* DO_THIS_LATER */ + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int get_async_struct(int line, ser_info_t **ret_info) +{ + struct serial_state *sstate; + + sstate = rs_table + line; + if (sstate->info) { + sstate->count++; + *ret_info = (ser_info_t *)sstate->info; + return 0; + } + else { + return -ENOMEM; + } +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_8xx_open(struct tty_struct *tty, struct file * filp) +{ + ser_info_t *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + retval = get_async_struct(line, &info); + if (retval) + return retval; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; + + MOD_INC_USE_COUNT; + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + change_speed(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static int inline line_info(char *buf, struct serial_state *state) +{ +#ifdef notdef + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; +#endif + int ret; + + ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", + state->line, + (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC", + (unsigned int)(state->port), state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + +#ifdef notdef + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + cli(); + status = serial_in(info, UART_MSR); + control = info ? info->MCR : serial_in(info, UART_MCR); + sti(); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); +#endif + return ret; +} + +int rs_8xx_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + len += line_info(page + len, &rs_table[i]); + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static _INLINE_ void show_serial_version(void) +{ + printk(KERN_INFO "%s version %s\n", serial_name, serial_version); +} + + +/* + * The serial console driver used during boot. Note that these names + * clash with those found in "serial.c", so we currently can't support + * the 16xxx uarts and these at the same time. I will fix this to become + * an indirect function call from tty_io.c (or something). + */ + +#ifdef CONFIG_SERIAL_CONSOLE + +/* + * Print a string to the serial port trying not to disturb any possible + * real use of the port... + * These funcitons work equally well for SCC, even though they are + * designed for SMC. Our only interests are the transmit/receive + * buffers, which are identically mapped for either the SCC or SMC. + */ +static void my_console_write(int idx, const char *s, + unsigned count) +{ + struct serial_state *ser; + ser_info_t *info; + unsigned i; + volatile cbd_t *bdp, *bdbase; + volatile smc_uart_t *up; + volatile u_char *cp; + + ser = rs_table + idx; + + /* If the port has been initialized for general use, we have + * to use the buffer descriptors allocated there. Otherwise, + * we simply use the single buffer allocated. + */ + if ((info = (ser_info_t *)ser->info) != NULL) { + bdp = info->tx_cur; + bdbase = info->tx_bd_base; + } + else { + /* Pointer to UART in parameter ram. + */ + up = (smc_uart_t *)&cpm2_immr->im_dprambase[ser->port]; + + /* Get the address of the host memory buffer. + */ + bdp = bdbase = (cbd_t *)&cpm2_immr->im_dprambase[up->smc_tbase]; + } + + /* + * We need to gracefully shut down the transmitter, disable + * interrupts, then send our bytes out. + */ + + /* + * Now, do each character. This is not as bad as it looks + * since this is a holding FIFO and not a transmitting FIFO. + * We could add the complexity of filling the entire transmit + * buffer, but we would just wait longer between accesses...... + */ + for (i = 0; i < count; i++, s++) { + /* Wait for transmitter fifo to empty. + * Ready indicates output is ready, and xmt is doing + * that, not that it is ready for us to send. + */ + while (bdp->cbd_sc & BD_SC_READY); + + /* Send the character out. + * If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + if ((uint)(bdp->cbd_bufaddr) > (uint)CPM_MAP_ADDR) + cp = (u_char *)(bdp->cbd_bufaddr); + else + cp = __va(bdp->cbd_bufaddr); + *cp = *s; + + bdp->cbd_datlen = 1; + bdp->cbd_sc |= BD_SC_READY; + + if (bdp->cbd_sc & BD_SC_WRAP) + bdp = bdbase; + else + bdp++; + + /* if a LF, also do CR... */ + if (*s == 10) { + while (bdp->cbd_sc & BD_SC_READY); + cp = __va(bdp->cbd_bufaddr); + *cp = 13; + bdp->cbd_datlen = 1; + bdp->cbd_sc |= BD_SC_READY; + + if (bdp->cbd_sc & BD_SC_WRAP) { + bdp = bdbase; + } + else { + bdp++; + } + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + while (bdp->cbd_sc & BD_SC_READY); + + if (info) + info->tx_cur = (cbd_t *)bdp; +} + +static void serial_console_write(struct console *c, const char *s, + unsigned count) +{ +#if defined(CONFIG_KGDB_CONSOLE) && !defined(CONFIG_USE_SERIAL2_KGDB) + /* Try to let stub handle output. Returns true if it did. */ + if (kgdb_output_string(s, count)) + return; +#endif + my_console_write(c->index, s, count); +} + +#ifdef CONFIG_XMON +int +xmon_8xx_write(const char *s, unsigned count) +{ + my_console_write(KGDB_SER_IDX, s, count); + return(count); +} +#endif + +#ifdef CONFIG_KGDB +void +putDebugChar(char ch) +{ + my_console_write(KGDB_SER_IDX, &ch, 1); +} +#endif + +#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) +/* + * Receive character from the serial port. This only works well + * before the port is initialize for real use. + */ +static int my_console_wait_key(int idx, int xmon, char *obuf) +{ + struct serial_state *ser; + u_char c, *cp; + ser_info_t *info; + volatile cbd_t *bdp; + volatile smc_uart_t *up; + int i; + + ser = rs_table + idx; + + /* Pointer to UART in parameter ram. + */ + up = (smc_uart_t *)&cpm2_immr->im_dprambase[ser->port]; + + /* Get the address of the host memory buffer. + * If the port has been initialized for general use, we must + * use information from the port structure. + */ + if ((info = (ser_info_t *)ser->info)) + bdp = info->rx_cur; + else + bdp = (cbd_t *)&cpm2_immr->im_dprambase[up->smc_rbase]; + + /* + * We need to gracefully shut down the receiver, disable + * interrupts, then read the input. + * XMON just wants a poll. If no character, return -1, else + * return the character. + */ + if (!xmon) { + while (bdp->cbd_sc & BD_SC_EMPTY); + } + else { + if (bdp->cbd_sc & BD_SC_EMPTY) + return -1; + } + + /* If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + if ((uint)(bdp->cbd_bufaddr) > (uint)CPM_MAP_ADDR) + cp = (u_char *)(bdp->cbd_bufaddr); + else + cp = __va(bdp->cbd_bufaddr); + + if (obuf) { + i = c = bdp->cbd_datlen; + while (i-- > 0) + *obuf++ = *cp++; + } + else { + c = *cp; + } + bdp->cbd_sc |= BD_SC_EMPTY; + + if (info) { + if (bdp->cbd_sc & BD_SC_WRAP) { + bdp = info->rx_bd_base; + } + else { + bdp++; + } + info->rx_cur = (cbd_t *)bdp; + } + + return((int)c); +} +#endif + +#ifdef CONFIG_XMON +int +xmon_8xx_read_poll(void) +{ + return(my_console_wait_key(KGDB_SER_IDX, 1, NULL)); +} + +int +xmon_8xx_read_char(void) +{ + return(my_console_wait_key(KGDB_SER_IDX, 0, NULL)); +} +#endif + +#ifdef CONFIG_KGDB +static char kgdb_buf[RX_BUF_SIZE], *kgdp; +static int kgdb_chars; + +char +getDebugChar(void) +{ + if (kgdb_chars <= 0) { + kgdb_chars = my_console_wait_key(KGDB_SER_IDX, 0, kgdb_buf); + kgdp = kgdb_buf; + } + kgdb_chars--; + + return(*kgdp++); +} + +void kgdb_interruptible(int yes) +{ + volatile smc_t *smcp; + + smcp = &cpm2_immr->im_smc[KGDB_SER_IDX]; + + if (yes == 1) + smcp->smc_smcm |= SMCM_RX; + else + smcp->smc_smcm &= ~SMCM_RX; +} + +void kgdb_map_scc(void) +{ + ushort serbase; + uint mem_addr; + volatile cbd_t *bdp; + volatile smc_uart_t *up; + + /* The serial port has already been initialized before + * we get here. We have to assign some pointers needed by + * the kernel, and grab a memory location in the CPM that will + * work until the driver is really initialized. + */ + cpm2_immr = (cpm2_map_t *)CPM_MAP_ADDR; + + /* Right now, assume we are using SMCs. + */ +#ifdef USE_KGDB_SMC2 + *(ushort *)(&cpm2_immr->im_dprambase[PROFF_SMC2_BASE]) = serbase = PROFF_SMC2; +#else + *(ushort *)(&cpm2_immr->im_dprambase[PROFF_SMC1_BASE]) = serbase = PROFF_SMC1; +#endif + up = (smc_uart_t *)&cpm2_immr->im_dprambase[serbase]; + + /* Allocate space for an input FIFO, plus a few bytes for output. + * Allocate bytes to maintain word alignment. + */ + mem_addr = (uint)(&cpm2_immr->im_dprambase[0x1000]); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + bdp = (cbd_t *)&cpm2_immr->im_dprambase[up->smc_rbase]; + bdp->cbd_bufaddr = mem_addr; + + bdp = (cbd_t *)&cpm2_immr->im_dprambase[up->smc_tbase]; + bdp->cbd_bufaddr = mem_addr+RX_BUF_SIZE; + + up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */ + up->smc_maxidl = RX_BUF_SIZE; +} +#endif + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Register console. + */ +long __init console_8xx_init(long kmem_start, long kmem_end) +{ + register_console(&sercons); + return kmem_start; +} + +#endif + +/* Default console baud rate as determined by the board information + * structure. + */ +static int baud_idx; + +/* + * The serial driver boot-time initialization code! + */ +int __init rs_8xx_init(void) +{ + struct serial_state * state; + ser_info_t *info; + uint mem_addr, dp_addr; + int i, j, idx; + uint page, sblock; + volatile cbd_t *bdp; + volatile cpm_cpm2_t *cp; + volatile smc_t *sp; + volatile smc_uart_t *up; + volatile scc_t *scp; + volatile scc_uart_t *sup; + volatile cpm2_map_t *immap; + volatile iop_cpm2_t *io; + + init_bh(SERIAL_BH, do_serial_bh); + + show_serial_version(); + + /* Initialize the tty_driver structure */ + + /*memset(&serial_driver, 0, sizeof(struct tty_driver));*/ + __clear_user(&serial_driver,sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "serial"; +#ifdef CONFIG_DEVFS_FS + serial_driver.name = "tts/%d"; +#else + serial_driver.name = "ttyS"; +#endif + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + baud_idx | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_8xx_open; + serial_driver.close = rs_8xx_close; + serial_driver.write = rs_8xx_write; + serial_driver.put_char = rs_8xx_put_char; + serial_driver.write_room = rs_8xx_write_room; + serial_driver.chars_in_buffer = rs_8xx_chars_in_buffer; + serial_driver.flush_buffer = rs_8xx_flush_buffer; + serial_driver.ioctl = rs_8xx_ioctl; + serial_driver.throttle = rs_8xx_throttle; + serial_driver.unthrottle = rs_8xx_unthrottle; + serial_driver.send_xchar = rs_8xx_send_xchar; + serial_driver.set_termios = rs_8xx_set_termios; + serial_driver.stop = rs_8xx_stop; + serial_driver.start = rs_8xx_start; + serial_driver.hangup = rs_8xx_hangup; + serial_driver.wait_until_sent = rs_8xx_wait_until_sent; + serial_driver.read_proc = rs_8xx_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; +#ifdef CONFIG_DEVFS_FS + callout_driver.name = "cua/%d"; +#else + callout_driver.name = "cua"; +#endif + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + immap = cpm2_immr; + cp = &immap->im_cpm; + io = &immap->im_ioport; + + /* This should have been done long ago by the early boot code, + * but do it again to make sure. + */ + *(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; + *(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2; + + /* Geeze, here we go....Picking I/O port bits....Lots of + * choices. If you don't like mine, pick your own. + * Configure SMCs Tx/Rx. SMC1 is only on Port D, SMC2 is + * only on Port A. You either pick 'em, or not. + */ +#ifndef SCC_CONSOLE + io->iop_ppard |= 0x00c00000; + io->iop_pdird |= 0x00400000; + io->iop_pdird &= ~0x00800000; + io->iop_psord &= ~0x00c00000; +#if USE_SMC2 + io->iop_ppara |= 0x00c00000; + io->iop_pdira |= 0x00400000; + io->iop_pdira &= ~0x00800000; + io->iop_psora &= ~0x00c00000; +#endif + + /* Configure SCC2 and SCC3. Be careful about the fine print. + * Secondary options are only available when you take away + * the primary option. Unless the pins are used for something + * else, SCC2 and SCC3 are on Port B. + * Port B, 8 - SCC3 TxD + * Port B, 12 - SCC2 TxD + * Port B, 14 - SCC3 RxD + * Port B, 15 - SCC2 RxD + */ + io->iop_pparb |= 0x008b0000; + io->iop_pdirb |= 0x00880000; + io->iop_psorb |= 0x00880000; + io->iop_pdirb &= ~0x00030000; + io->iop_psorb &= ~0x00030000; + + /* Wire BRG1 to SMC1 and BRG2 to SMC2. + */ + immap->im_cpmux.cmx_smr = 0; + + /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and + * BRG4 to SCC3. + */ + immap->im_cpmux.cmx_scr &= ~0x00ffff00; + immap->im_cpmux.cmx_scr |= 0x00121b00; +#else + io->iop_pparb |= 0x008b0000; + io->iop_pdirb |= 0x00880000; + io->iop_psorb |= 0x00880000; + io->iop_pdirb &= ~0x00030000; + io->iop_psorb &= ~0x00030000; + + /* Use Port D for SCC1 instead of other functions. + */ + io->iop_ppard |= 0x00000003; + io->iop_psord &= ~0x00000001; /* Rx */ + io->iop_psord |= 0x00000002; /* Tx */ + io->iop_pdird &= ~0x00000001; /* Rx */ + io->iop_pdird |= 0x00000002; /* Tx */ + + /* Connect SCC1, SCC2, SCC3 to NMSI. Connect BRG1 to SCC1, + * BRG2 to SCC2, BRG3 to SCC3. + */ + immap->im_cpmux.cmx_scr &= ~0xffffff00; + immap->im_cpmux.cmx_scr |= 0x00091200; +#endif + + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; + state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; + state->callout_termios = callout_driver.init_termios; + state->normal_termios = serial_driver.init_termios; + state->icount.cts = state->icount.dsr = + state->icount.rng = state->icount.dcd = 0; + state->icount.rx = state->icount.tx = 0; + state->icount.frame = state->icount.parity = 0; + state->icount.overrun = state->icount.brk = 0; + printk (KERN_INFO "ttyS%d on %s%d at 0x%04x, BRG%d\n", + i, + (state->smc_scc_num < SCC_NUM_BASE) ? "SMC" : "SCC", + PORT_NUM(state->smc_scc_num) + 1, + (unsigned int)(state->port), + state->smc_scc_num + 1); +#ifdef CONFIG_SERIAL_CONSOLE + /* If we just printed the message on the console port, and + * we are about to initialize it for general use, we have + * to wait a couple of character times for the CR/NL to + * make it out of the transmit buffer. + */ + if (i == CONFIG_SERIAL_CONSOLE_PORT) + mdelay(300); +#endif + info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); + if (info) { + /*memset(info, 0, sizeof(ser_info_t));*/ + __clear_user(info,sizeof(ser_info_t)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->magic = SERIAL_MAGIC; + info->flags = state->flags; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; + info->line = i; + info->state = state; + state->info = (struct async_struct *)info; + + /* We need to allocate a transmit and receive buffer + * descriptors from dual port ram, and a character + * buffer area from host mem. + */ + dp_addr = cpm2_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); + + /* Allocate space for FIFOs in the host memory. + */ + mem_addr = cpm2_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; + info->rx_cur = info->rx_bd_base = (cbd_t *)bdp; + + for (j=0; j<(RX_NUM_FIFO-1); j++) { + bdp->cbd_bufaddr = __pa(mem_addr); + bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; + mem_addr += RX_BUF_SIZE; + bdp++; + } + bdp->cbd_bufaddr = __pa(mem_addr); + bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + + if ((idx = state->smc_scc_num) < SCC_NUM_BASE) { + sp = &immap->im_smc[idx]; + up = (smc_uart_t *)&immap->im_dprambase[state->port]; + up->smc_rbase = dp_addr; + } + else { + scp = &immap->im_scc[idx - SCC_IDX_BASE]; + sup = (scc_uart_t *)&immap->im_dprambase[state->port]; + scp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + sup->scc_genscc.scc_rbase = dp_addr; + } + + dp_addr = cpm2_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); + + /* Allocate space for FIFOs in the host memory. + */ + mem_addr = cpm2_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); + + /* Set the physical address of the host memory + * buffers in the buffer descriptors, and the + * virtual address for us to work with. + */ + bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; + info->tx_cur = info->tx_bd_base = (cbd_t *)bdp; + + for (j=0; j<(TX_NUM_FIFO-1); j++) { + bdp->cbd_bufaddr = __pa(mem_addr); + bdp->cbd_sc = BD_SC_INTRPT; + mem_addr += TX_BUF_SIZE; + bdp++; + } + bdp->cbd_bufaddr = __pa(mem_addr); + bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); + + if (idx < SCC_NUM_BASE) { + up->smc_tbase = dp_addr; + + /* Set up the uart parameters in the + * parameter ram. + */ + up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; + up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle charater + * time requires some additional tuning. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + up->smc_brkcr = 1; + + /* Send the CPM an initialize command. + */ + if (state->smc_scc_num == 0) { + page = CPM_CR_SMC1_PAGE; + sblock = CPM_CR_SMC1_SBLOCK; + } + else { + page = CPM_CR_SMC2_PAGE; + sblock = CPM_CR_SMC2_SBLOCK; + } + + cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Disable all interrupts and clear all pending + * events. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + } + else { + sup->scc_genscc.scc_tbase = dp_addr; + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle charater + * time requires some additional tuning. + */ + sup->scc_genscc.scc_mrblr = 1; + sup->scc_maxidl = 0; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ +#ifdef SCC_CONSOLE + switch (state->smc_scc_num) { + case 0: + page = CPM_CR_SCC1_PAGE; + sblock = CPM_CR_SCC1_SBLOCK; + break; + case 1: + page = CPM_CR_SCC2_PAGE; + sblock = CPM_CR_SCC2_SBLOCK; + break; + case 2: + page = CPM_CR_SCC3_PAGE; + sblock = CPM_CR_SCC3_SBLOCK; + break; + } +#else + if (state->smc_scc_num == 2) { + page = CPM_CR_SCC2_PAGE; + sblock = CPM_CR_SCC2_SBLOCK; + } + else { + page = CPM_CR_SCC3_PAGE; + sblock = CPM_CR_SCC3_SBLOCK; + } +#endif + + cp->cp_cpcr = mk_cr_cmd(page, sblock, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + scp->scc_gsmrh = 0; + scp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + scp->scc_sccm = 0; + scp->scc_scce = 0xffff; + scp->scc_dsr = 0x7e7e; + scp->scc_psmr = 0x3000; + } + + /* Install interrupt handler. + */ + request_irq(state->irq, rs_8xx_interrupt, 0, "uart", + info); + + /* Set up the baud rate generator. + */ + cpm2_setbrg(state->smc_scc_num, + baud_table[baud_idx]); + + /* If the port is the console, enable Rx and Tx. + */ +#ifdef CONFIG_SERIAL_CONSOLE + if (i == CONFIG_SERIAL_CONSOLE_PORT) { + if (idx < SCC_NUM_BASE) + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; + else + scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + } +#endif + } + } + return 0; +} + +/* This must always be called before the rs_8xx_init() function, otherwise + * it blows away the port control information. +*/ +static int __init serial_console_setup(struct console *co, char *options) +{ + struct serial_state *ser; + uint mem_addr, dp_addr, bidx; + volatile cbd_t *bdp; + volatile cpm_cpm2_t *cp; + volatile cpm2_map_t *immap; +#ifndef SCC_CONSOLE + volatile smc_t *sp; + volatile smc_uart_t *up; +#endif + volatile scc_t *scp; + volatile scc_uart_t *sup; + volatile iop_cpm2_t *io; + bd_t *bd; + + bd = (bd_t *)__res; + + for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++) + if (bd->bi_baudrate == baud_table[bidx]) + break; + + co->cflag = CREAD|CLOCAL|bidx|CS8; + baud_idx = bidx; + + ser = rs_table + co->index; + + immap = cpm2_immr; + cp = &immap->im_cpm; + io = &immap->im_ioport; + +#ifdef SCC_CONSOLE + scp = (scc_t *)&(immap->im_scc[SCC_CONSOLE-1]); + sup = (scc_uart_t *)&immap->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)]; + scp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + scp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Use Port D for SCC1 instead of other functions. + */ + io->iop_ppard |= 0x00000003; + io->iop_psord &= ~0x00000001; /* Rx */ + io->iop_psord |= 0x00000002; /* Tx */ + io->iop_pdird &= ~0x00000001; /* Rx */ + io->iop_pdird |= 0x00000002; /* Tx */ + +#else + /* This should have been done long ago by the early boot code, + * but do it again to make sure. + */ + *(ushort *)(&immap->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1; + *(ushort *)(&immap->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2; + + /* Right now, assume we are using SMCs. + */ + sp = &immap->im_smc[ser->smc_scc_num]; + + /* When we get here, the CPM has been reset, so we need + * to configure the port. + * We need to allocate a transmit and receive buffer descriptor + * from dual port ram, and a character buffer area from host mem. + */ + up = (smc_uart_t *)&immap->im_dprambase[ser->port]; + + /* Disable transmitter/receiver. + */ + sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); + + /* Use Port D for SMC1 instead of other functions. + */ + io->iop_ppard |= 0x00c00000; + io->iop_pdird |= 0x00400000; + io->iop_pdird &= ~0x00800000; + io->iop_psord &= ~0x00c00000; +#endif + + /* Allocate space for two buffer descriptors in the DP ram. + */ + dp_addr = cpm2_dpalloc(sizeof(cbd_t) * 2, 8); + + /* Allocate space for two 2 byte FIFOs in the host memory. + */ + mem_addr = cpm2_hostalloc(4, 1); + + /* Set the physical address of the host memory buffers in + * the buffer descriptors. + */ + bdp = (cbd_t *)&immap->im_dprambase[dp_addr]; + bdp->cbd_bufaddr = __pa(mem_addr); + (bdp+1)->cbd_bufaddr = __pa(mem_addr+2); + + /* For the receive, set empty and wrap. + * For transmit, set wrap. + */ + bdp->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP; + (bdp+1)->cbd_sc = BD_SC_WRAP; + + /* Set up the uart parameters in the parameter ram. + */ +#ifdef SCC_CONSOLE + sup->scc_genscc.scc_rbase = dp_addr; + sup->scc_genscc.scc_tbase = dp_addr + sizeof(cbd_t); + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB; + sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + sup->scc_genscc.scc_mrblr = 1; + sup->scc_maxidl = 0; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + scp->scc_gsmrh = 0; + scp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + scp->scc_sccm = 0; + scp->scc_scce = 0xffff; + scp->scc_dsr = 0x7e7e; + scp->scc_psmr = 0x3000; + + /* Wire BRG1 to SCC1. The serial init will take care of + * others. + */ + immap->im_cpmux.cmx_scr = 0; + + /* Set up the baud rate generator. + */ + cpm2_setbrg(ser->smc_scc_num, bd->bi_baudrate); + + scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#else + up->smc_rbase = dp_addr; /* Base of receive buffer desc. */ + up->smc_tbase = dp_addr+sizeof(cbd_t); /* Base of xmt buffer desc. */ + up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB; + up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB; + + /* Set this to 1 for now, so we get single character interrupts. + */ + up->smc_mrblr = 1; /* receive buffer length */ + up->smc_maxidl = 0; /* wait forever for next char */ + + /* Send the CPM an initialize command. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + + /* Set up the baud rate generator. + */ + cpm2_setbrg(ser->smc_scc_num, bd->bi_baudrate); + + /* And finally, enable Rx and Tx. + */ + sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN; +#endif + + return 0; +} diff -urN linux-2.4.25/arch/ppc/kernel/Makefile linux-2.4.26/arch/ppc/kernel/Makefile --- linux-2.4.25/arch/ppc/kernel/Makefile 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/Makefile 2004-04-14 06:05:27.000000000 -0700 @@ -32,7 +32,8 @@ O_TARGET := kernel.o export-objs := ppc_ksyms.o time.o ocp.o ppc4xx_setup.o \ - ppc4xx_dma.o ppc4xx_sgdma.o + ppc4xx_dma.o ppc4xx_sgdma.o \ + ppc4xx_stbdma.o obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ @@ -53,14 +54,17 @@ obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o endif -obj-$(CONFIG_40x) += ppc4xx_setup.o -obj-$(CONFIG_4xx) += ocp.o ppc4xx_pic.o todc_time.o +obj-$(CONFIG_PPC_OCP) += ocp.o +obj-$(CONFIG_40x) += ppc4xx_setup.o ppc4xx_pic.o +obj-$(CONFIG_4xx) += todc_time.o +obj-$(CONFIG_STBXXX_DMA) += ppc4xx_stbdma.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_40x) += ppc405_pci.o obj-$(CONFIG_4xx) += indirect_pci.o pci_auto.o endif -obj-$(CONFIG_44x) += ibm44x_common.o +obj-$(CONFIG_44x) += ppc4xx_pic.o ibm44x_common.o obj-$(CONFIG_440GP) += ibm440gp_common.o +obj-$(CONFIG_440GX) += ibm440gx_common.o obj-$(CONFIG_PPC4xx_DMA) += ppc4xx_dma.o obj-$(CONFIG_PPC4xx_EDMA) += ppc4xx_sgdma.o obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o @@ -85,7 +89,7 @@ obj-$(CONFIG_SANDPOINT) += i8259.o open_pic.o mpc10x_common.o \ pci_auto.o indirect_pci.o todc_time.o obj-$(CONFIG_SPRUCE) += indirect_pci.o pci_auto.o todc_time.o -obj-$(CONFIG_8260) += m8260_setup.o ppc8260_pic.o +obj-$(CONFIG_8260) += m8260_setup.o cpm2_pic.o obj-$(CONFIG_BOOTX_TEXT) += btext.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.25/arch/ppc/kernel/cpm2_pic.c linux-2.4.26/arch/ppc/kernel/cpm2_pic.c --- linux-2.4.25/arch/ppc/kernel/cpm2_pic.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/cpm2_pic.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include "cpm2_pic.h" + +/* The CPM2 internal interrupt controller. It is usually + * the only interrupt controller. + * There are two 32-bit registers (high/low) for up to 64 + * possible interrupts. + * + * Now, the fun starts.....Interrupt Numbers DO NOT MAP + * in a simple arithmetic fashion to mask or pending registers. + * That is, interrupt 4 does not map to bit position 4. + * We create two tables, indexed by vector number, to indicate + * which register to use and which bit in the register to use. + */ +static u_char irq_to_siureg[] = { + 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, + 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 +}; + +static u_char irq_to_siubit[] = { + 31, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, + 29, 30, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 31, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +static void cpm2_mask_irq(unsigned int irq_nr) +{ + int bit, word; + volatile uint *simr; + + bit = irq_to_siubit[irq_nr]; + word = irq_to_siureg[irq_nr]; + + simr = &(cpm2_immr->im_intctl.ic_simrh); + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + simr[word] = ppc_cached_irq_mask[word]; +} + +static void cpm2_unmask_irq(unsigned int irq_nr) +{ + int bit, word; + volatile uint *simr; + + bit = irq_to_siubit[irq_nr]; + word = irq_to_siureg[irq_nr]; + + simr = &(cpm2_immr->im_intctl.ic_simrh); + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); + simr[word] = ppc_cached_irq_mask[word]; +} + +static void cpm2_mask_and_ack(unsigned int irq_nr) +{ + int bit, word; + volatile uint *simr, *sipnr; + + bit = irq_to_siubit[irq_nr]; + word = irq_to_siureg[irq_nr]; + + simr = &(cpm2_immr->im_intctl.ic_simrh); + sipnr = &(cpm2_immr->im_intctl.ic_sipnrh); + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + simr[word] = ppc_cached_irq_mask[word]; + sipnr[word] = 1 << (31 - bit); +} + +static void cpm2_end_irq(unsigned int irq_nr) +{ + int bit, word; + volatile uint *simr; + + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + + bit = irq_to_siubit[irq_nr]; + word = irq_to_siureg[irq_nr]; + + simr = &(cpm2_immr->im_intctl.ic_simrh); + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); + simr[word] = ppc_cached_irq_mask[word]; + } +} + +struct hw_interrupt_type cpm2_pic = { + " CPM2 SIU ", + NULL, + NULL, + cpm2_unmask_irq, + cpm2_mask_irq, + cpm2_mask_and_ack, + cpm2_end_irq, + 0 +}; + +/* Return an interrupt vector or -1 if no interrupt is pending. */ +int +cpm2_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits; + + /* For CPM2, read the SIVEC register and shift the bits down + * to get the irq number. */ + bits = cpm2_immr->im_intctl.ic_sivec; + irq = bits >> 26; + + if (irq == 0) /* 0 --> no irq is pending */ + irq = -1; + + return irq; +} + diff -urN linux-2.4.25/arch/ppc/kernel/cpm2_pic.h linux-2.4.26/arch/ppc/kernel/cpm2_pic.h --- linux-2.4.25/arch/ppc/kernel/cpm2_pic.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/cpm2_pic.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,13 @@ +#ifndef _PPC_KERNEL_CPM2_H +#define _PPC_KERNEL_CPM2_H + +#include + +extern struct hw_interrupt_type cpm2_pic; + +void cpm2_pic_init(void); +void cpm2_do_IRQ(struct pt_regs *regs, + int cpu); +int cpm2_get_irq(struct pt_regs *regs); + +#endif /* _PPC_KERNEL_CPM2_H */ diff -urN linux-2.4.25/arch/ppc/kernel/cputable.c linux-2.4.26/arch/ppc/kernel/cputable.c --- linux-2.4.25/arch/ppc/kernel/cputable.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/cputable.c 2004-04-14 06:05:27.000000000 -0700 @@ -417,6 +417,20 @@ 32, 32, 0, /*__setup_cpu_440 */ }, + { /* 440GX Rev. B */ + 0xf0000fff, 0x50000851, "440GX Rev. B", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + 32, 32, + 0, /*__setup_cpu_440 */ + }, + { /* 440GX Rev. B1 (2.1) */ + 0xf0000fff, 0x50000852, "440GX Rev. B1 (2.1)", + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + 32, 32, + 0, /*__setup_cpu_440 */ + }, #endif /* CONFIG_44x */ #if !CLASSIC_PPC { /* default match */ diff -urN linux-2.4.25/arch/ppc/kernel/entry.S linux-2.4.26/arch/ppc/kernel/entry.S --- linux-2.4.25/arch/ppc/kernel/entry.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/entry.S 2004-04-14 06:05:27.000000000 -0700 @@ -43,6 +43,10 @@ * Handle a system call. */ .text + .stabs "arch/ppc/kernel/",N_SO,0,0,0f + .stabs "entry.S",N_SO,0,0,0f +0: + _GLOBAL(DoSyscall) stw r0,THREAD+LAST_SYSCALL(r2) lwz r11,_CCR(r1) /* Clear SO bit in CR */ diff -urN linux-2.4.25/arch/ppc/kernel/head.S linux-2.4.26/arch/ppc/kernel/head.S --- linux-2.4.25/arch/ppc/kernel/head.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/head.S 2004-04-14 06:05:27.000000000 -0700 @@ -69,6 +69,9 @@ #endif /* CONFIG_PPC64BRIDGE */ .text + .stabs "arch/ppc/kernel/",N_SO,0,0,0f + .stabs "head.S",N_SO,0,0,0f +0: .globl _stext _stext: diff -urN linux-2.4.25/arch/ppc/kernel/head_44x.S linux-2.4.26/arch/ppc/kernel/head_44x.S --- linux-2.4.25/arch/ppc/kernel/head_44x.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/head_44x.S 2004-04-14 06:05:27.000000000 -0700 @@ -30,6 +30,16 @@ #define STND_EXC 0 #define CRIT_EXC 1 +#ifdef CONFIG_440A +#define MCHK_EXC 2 +#define __SPRN_MCSRR0 SPRN_MCSRR0 +#define __SPRN_MCSRR1 SPRN_MCSRR1 +#else +#define MCHK_EXC CRIT_EXC +#define __SPRN_MCSRR0 SPRN_CSRR0 +#define __SPRN_MCSRR1 SPRN_CSRR1 +#endif + /* * Macros */ @@ -396,7 +406,25 @@ /* Machine Check Interrupt */ /* TODO: provide bus error register status */ - CRIT_EXCEPTION(0x200, MachineCheck,MachineCheckException); + START_EXCEPTION(MachineCheck) + COMMON_PROLOG; + mfspr r22,__SPRN_MCSRR0 /* Faulting instruction address */ + lis r20,MSR_WE@h + mfspr r23,__SPRN_MCSRR1 /* MSR at the time of fault */ + andc r23,r23,r20 /* disable processor wait state */ + COMMON_EPILOG; +#ifdef CONFIG_440A + lis r20,MCSR_MCS@h + mfspr r4,SPRN_MCSR /* We may want to access original + MCSR as arg2 in the future. --ebs */ + mtspr SPRN_MCSR,r20 /* Clear Machine Check Summary field */ +#endif + mfspr r5,SPRN_ESR /* Grab the ESR, save it */ + stw r5,_ESR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r7,MCHK_EXC + li r20,MSR_KERNEL + FINISH_EXCEPTION(0x200, MachineCheckException) /* Data Storage Interrupt */ START_EXCEPTION(DataStorage) @@ -415,7 +443,7 @@ * offending address and handle it. */ mfspr r20, SPRN_ESR - andis. r20, r20, ESR_ST@h + andis. r20, r20, ESR_DST@h beq 2f mfspr r20, SPRN_DEAR /* Get faulting address */ @@ -994,7 +1022,7 @@ lwz r24,0(r23) /* Virtual address of the handler */ lwz r23,4(r23) /* Handler return pointer */ cmpwi cr0,r7,STND_EXC /* What type of exception is this? */ - bne 3f /* It is a critical exception... */ + bne 3f /* It is a critical/machine check exception... */ /* Standard exception jump path */ @@ -1010,19 +1038,23 @@ mtspr SPRN_SRR1,r20 /* Set up the machine state register */ mtlr r23 /* Set up the return pointer */ SYNC - /* We shouldn't need a 405 erratum #77 workaround here, because we're not - * actually returning to the interrupted instruction yet. */ rfi - /* Critical exception jump path + /* Critical/Machine check exception jump path */ - -3: mtspr SPRN_CSRR0,r24 /* Set up the instruction pointer */ - mtspr SPRN_CSRR1,r20 /* Set up the machine state register */ +3: cmpwi r7,CRIT_EXC /* Critical or machine check ? */ mtlr r23 /* Set up the return pointer */ + bne 4f + mtspr SPRN_CSRR0,r24 /* Set up the instruction pointer */ + mtspr SPRN_CSRR1,r20 /* Set up the machine state register */ SYNC rfci +4: mtspr SPRN_MCSRR0,r24 /* Set up the instruction pointer */ + mtspr SPRN_MCSRR1,r20 /* Set up the machine state register */ + SYNC + RFMCI + /* On kernel stack overlow, load up an initial stack pointer and call * StackOverflow(regs), which should NOT return. */ diff -urN linux-2.4.25/arch/ppc/kernel/ibm440gp_common.c linux-2.4.26/arch/ppc/kernel/ibm440gp_common.c --- linux-2.4.25/arch/ppc/kernel/ibm440gp_common.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ibm440gp_common.c 2004-04-14 06:05:27.000000000 -0700 @@ -25,7 +25,7 @@ /* * Calculate 440GP clocks */ -void __init ibm440gp_get_clocks(struct ibm440gp_clocks* p, unsigned int sys_clk, +void __init ibm440gp_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk, unsigned int ser_clk) { u32 cpc0_sys0 = mfdcr(DCRN_CPC0_SYS0); @@ -68,11 +68,11 @@ if (cpc0_cr0 & 0x00400000){ /* External UART clock */ - p->uart = ser_clk; + p->uart0 = p->uart1 = ser_clk; } else { /* Internal UART clock */ u32 uart_div = ((cpc0_cr0 >> 16) & 0x1f) + 1; - p->uart = p->plb / uart_div; + p->uart0 = p->uart1 = p->plb / uart_div; } } diff -urN linux-2.4.25/arch/ppc/kernel/ibm440gp_common.h linux-2.4.26/arch/ppc/kernel/ibm440gp_common.h --- linux-2.4.25/arch/ppc/kernel/ibm440gp_common.h 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ibm440gp_common.h 2004-04-14 06:05:27.000000000 -0700 @@ -20,24 +20,14 @@ #include #include - -/* - * All clocks are in Hz - */ -struct ibm440gp_clocks { - unsigned int cpu; /* CPUCoreClk */ - unsigned int plb; /* PLBClk */ - unsigned int opb; /* OPBClk */ - unsigned int ebc; /* PerClk */ - unsigned int uart; -}; +#include /* * Please, refer to the Figure 13.1 in 440GP user manual * * if internal UART clock is used, ser_clk is ignored */ -void ibm440gp_get_clocks(struct ibm440gp_clocks*, unsigned int sys_clk, +void ibm440gp_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk, unsigned int ser_clk) __init; #endif /* __ASSEMBLY__ */ diff -urN linux-2.4.25/arch/ppc/kernel/ibm440gx_common.c linux-2.4.26/arch/ppc/kernel/ibm440gx_common.c --- linux-2.4.25/arch/ppc/kernel/ibm440gx_common.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ibm440gx_common.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,191 @@ +/* + * arch/ppc/kernel/ibm440gx_common.c + * + * PPC440GX system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include + +/* + * Calculate 440GX clocks + */ +static inline u32 __fix_zero(u32 v, u32 def){ + return v ? v : def; +} + +void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk, + unsigned int ser_clk) +{ + u32 pllc = CPR_READ(DCRN_CPR_PLLC); + u32 plld = CPR_READ(DCRN_CPR_PLLD); + u32 uart0 = SDR_READ(DCRN_SDR_UART0); + u32 uart1 = SDR_READ(DCRN_SDR_UART1); + + /* Dividers */ + u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32); + u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16); + u32 fwdvb = __fix_zero((plld >> 8) & 7, 8); + u32 lfbdv = __fix_zero(plld & 0x3f, 64); + u32 pradv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMAD) >> 24) & 7, 8); + u32 prbdv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMBD) >> 24) & 7, 8); + u32 opbdv0 = __fix_zero((CPR_READ(DCRN_CPR_OPBD) >> 24) & 3, 4); + u32 perdv0 = __fix_zero((CPR_READ(DCRN_CPR_PERD) >> 24) & 3, 4); + + /* Input clocks for primary dividers */ + u32 clk_a, clk_b; + + if (pllc & 0x40000000){ + u32 m; + + /* Feedback path */ + switch ((pllc >> 24) & 7){ + case 0: + /* PLLOUTx */ + m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv; + break; + case 1: + /* CPU */ + m = fwdva * pradv0; + break; + case 5: + /* PERClk */ + m = fwdvb * prbdv0 * opbdv0 * perdv0; + break; + default: + printk(KERN_EMERG "invalid PLL feedback source\n"); + goto bypass; + } + m *= fbdv; + p->vco = sys_clk * m; + clk_a = p->vco / fwdva; + clk_b = p->vco / fwdvb; + } + else { +bypass: + /* Bypass system PLL */ + p->vco = 0; + clk_a = clk_b = sys_clk; + } + + p->cpu = clk_a / pradv0; + p->plb = clk_b / prbdv0; + p->opb = p->plb / opbdv0; + p->ebc = p->opb / perdv0; + + /* UARTs clock */ + if (uart0 & 0x00800000) + p->uart0 = ser_clk; + else + p->uart0 = p->plb / __fix_zero(uart0 & 0xff, 256); + + if (uart1 & 0x00800000) + p->uart1 = ser_clk; + else + p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256); +} + +/* Enable L2 cache (call with IRQs disabled) */ +void __init ibm440gx_l2c_enable(void){ + u32 r; + + asm volatile ("sync" ::: "memory"); + + /* Disable SRAM */ + mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE); + mtdcr(DCRN_SRAM0_SB0CR, mfdcr(DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB1CR, mfdcr(DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB2CR, mfdcr(DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK); + mtdcr(DCRN_SRAM0_SB3CR, mfdcr(DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK); + + /* Enable L2_MODE without ICU/DCU */ + r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK); + r |= L2C_CFG_L2M | L2C_CFG_SS_256; + mtdcr(DCRN_L2C0_CFG, r); + + mtdcr(DCRN_L2C0_ADDR, 0); + + /* Hardware Clear Command */ + mtdcr(DCRN_L2C0_CMD, L2C_CMD_HCC); + while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ; + + /* Clear Cache Parity and Tag Errors */ + mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE); + + /* Enable 64G snoop region starting at 0 */ + r = mfdcr(DCRN_L2C0_SNP0) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK); + r |= L2C_SNP_SSR_32G | L2C_SNP_ESR; + mtdcr(DCRN_L2C0_SNP0, r); + + r = mfdcr(DCRN_L2C0_SNP1) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK); + r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR; + mtdcr(DCRN_L2C0_SNP1, r); + + asm volatile ("sync" ::: "memory"); + + /* Enable ICU/DCU ports */ + r = mfdcr(DCRN_L2C0_CFG); + r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM + | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI | L2C_CFG_CPEI + | L2C_CFG_NAM | L2C_CFG_NBRM); + r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN + | L2C_CFG_SMCM; + mtdcr(DCRN_L2C0_CFG, r); + + asm volatile ("sync; isync" ::: "memory"); +} + +/* Disable L2 cache (call with IRQs disabled) */ +void __init ibm440gx_l2c_disable(void){ + u32 r; + + asm volatile ("sync" ::: "memory"); + + /* Disable L2C mode */ + r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_L2M | L2C_CFG_ICU | L2C_CFG_DCU); + mtdcr(DCRN_L2C0_CFG, r); + + /* Enable SRAM */ + mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) | SRAM_DPC_ENABLE); + mtdcr(DCRN_SRAM0_SB0CR, + SRAM_SBCR_BAS0 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB1CR, + SRAM_SBCR_BAS1 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB2CR, + SRAM_SBCR_BAS2 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + mtdcr(DCRN_SRAM0_SB3CR, + SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW); + + asm volatile ("sync; isync" ::: "memory"); +} + +int ibm440gx_show_cpuinfo(struct seq_file *m){ + + u32 l2c_cfg = mfdcr(DCRN_L2C0_CFG); + const char* s; + if (l2c_cfg & L2C_CFG_L2M){ + switch (l2c_cfg & (L2C_CFG_ICU | L2C_CFG_DCU)){ + case L2C_CFG_ICU: s = "I-Cache only"; break; + case L2C_CFG_DCU: s = "D-Cache only"; break; + default: s = "I-Cache/D-Cache"; break; + } + } + else + s = "disabled"; + + seq_printf(m, "L2-Cache\t: %s (0x%08x 0x%08x)\n", s, + l2c_cfg, mfdcr(DCRN_L2C0_SR)); +} + diff -urN linux-2.4.25/arch/ppc/kernel/ibm440gx_common.h linux-2.4.26/arch/ppc/kernel/ibm440gx_common.h --- linux-2.4.25/arch/ppc/kernel/ibm440gx_common.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ibm440gx_common.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,42 @@ +/* + * arch/ppc/kernel/ibm440gx_common.h + * + * PPC440GX system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * 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. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_SYSLIB_IBM440GX_COMMON_H +#define __PPC_SYSLIB_IBM440GX_COMMON_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +/* + * Please, refer to the Figure 14.1 in 440GX user manual + * + * if internal UART clock is used, ser_clk is ignored + */ +void ibm440gx_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk, + unsigned int ser_clk) __init; + +/* Enable L2 cache */ +void ibm440gx_l2c_enable(void) __init; + +/* Add L2C info to /proc/cpuinfo */ +int ibm440gx_show_cpuinfo(struct seq_file*); + +#endif /* __ASSEMBLY__ */ +#endif /* __PPC_SYSLIB_IBM440GX_COMMON_H */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/kernel/ibm44x_common.h linux-2.4.26/arch/ppc/kernel/ibm44x_common.h --- linux-2.4.25/arch/ppc/kernel/ibm44x_common.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ibm44x_common.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,36 @@ +/* + * arch/ppc/kernel/ibm44x_common.h + * + * PPC44x system library + * + * Eugene Surovegin or + * Copyright (c) 2003 Zultys Technologies + * + * 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. + * + */ +#ifdef __KERNEL__ +#ifndef __PPC_SYSLIB_IBM44x_COMMON_H +#define __PPC_SYSLIB_IBM44x_COMMON_H + +#ifndef __ASSEMBLY__ + +/* + * All clocks are in Hz + */ +struct ibm44x_clocks { + unsigned int vco; /* VCO, 0 if system PLL is bypassed */ + unsigned int cpu; /* CPUCoreClk */ + unsigned int plb; /* PLBClk */ + unsigned int opb; /* OPBClk */ + unsigned int ebc; /* PerClk */ + unsigned int uart0; + unsigned int uart1; +}; + +#endif /* __ASSEMBLY__ */ +#endif /* __PPC_SYSLIB_IBM44x_COMMON_H */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/kernel/m8260_setup.c linux-2.4.26/arch/ppc/kernel/m8260_setup.c --- linux-2.4.25/arch/ppc/kernel/m8260_setup.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/arch/ppc/kernel/m8260_setup.c 2004-04-14 06:05:27.000000000 -0700 @@ -40,12 +40,12 @@ #include #include #include -#include +#include #include #include #include -#include "ppc8260_pic.h" +#include "cpm2_pic.h" static int m8260_set_rtc_time(unsigned long time); static unsigned long m8260_get_rtc_time(void); @@ -53,14 +53,14 @@ unsigned char __res[sizeof(bd_t)]; -extern void m8260_cpm_reset(void); +extern void cpm2_reset(void); static void __init m8260_setup_arch(void) { /* Reset the Communication Processor Module. */ - m8260_cpm_reset(); + cpm2_reset(); } static void @@ -172,18 +172,18 @@ void cpm_interrupt_init(void); #if 0 - ppc8260_pic.irq_offset = 0; + cpm2_pic.irq_offset = 0; #endif for ( i = 0 ; i < NR_SIU_INTS ; i++ ) - irq_desc[i].handler = &ppc8260_pic; + irq_desc[i].handler = &cpm2_pic; /* Initialize the default interrupt mapping priorities, * in case the boot rom changed something on us. */ - immr->im_intctl.ic_sicr = 0; - immr->im_intctl.ic_siprr = 0x05309770; - immr->im_intctl.ic_scprrh = 0x05309770; - immr->im_intctl.ic_scprrl = 0x05309770; + cpm2_immr->im_intctl.ic_sicr = 0; + cpm2_immr->im_intctl.ic_siprr = 0x05309770; + cpm2_immr->im_intctl.ic_scprrh = 0x05309770; + cpm2_immr->im_intctl.ic_scprrl = 0x05309770; } @@ -242,7 +242,7 @@ ppc_md.show_percpuinfo = m8260_show_percpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = m8260_init_IRQ; - ppc_md.get_irq = m8260_get_irq; + ppc_md.get_irq = cpm2_get_irq; ppc_md.init = NULL; ppc_md.restart = m8260_restart; diff -urN linux-2.4.25/arch/ppc/kernel/misc.S linux-2.4.26/arch/ppc/kernel/misc.S --- linux-2.4.25/arch/ppc/kernel/misc.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/misc.S 2004-04-14 06:05:27.000000000 -0700 @@ -694,29 +694,36 @@ _GLOBAL(copy_page) addi r3,r3,-4 addi r4,r4,-4 + +#ifdef CONFIG_8xx + /* don't use prefetch on 8xx */ + li r0,4096/L1_CACHE_LINE_SIZE + mtctr r0 +1: COPY_16_BYTES + bdnz 1b + blr + +#else /* not 8xx, we can prefetch */ li r5,4 -#ifndef CONFIG_8xx -#if MAX_L1_COPY_PREFETCH > 1 - li r0,MAX_L1_COPY_PREFETCH +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH li r11,4 mtctr r0 11: dcbt r11,r4 addi r11,r11,L1_CACHE_LINE_SIZE bdnz 11b -#else /* MAX_L1_COPY_PREFETCH == 1 */ +#else /* MAX_COPY_PREFETCH == 1 */ dcbt r5,r4 li r11,L1_CACHE_LINE_SIZE+4 -#endif /* MAX_L1_COPY_PREFETCH */ -#endif /* CONFIG_8xx */ - - li r0,4096/L1_CACHE_LINE_SIZE +#endif /* MAX_COPY_PREFETCH */ + li r0,4096/L1_CACHE_LINE_SIZE - MAX_COPY_PREFETCH + crclr 4*cr0+eq +2: mtctr r0 1: -#ifndef CONFIG_8xx dcbt r11,r4 dcbz r5,r3 -#endif COPY_16_BYTES #if L1_CACHE_LINE_SIZE >= 32 COPY_16_BYTES @@ -732,7 +739,12 @@ #endif #endif bdnz 1b - blr + beqlr + crnot 4*cr0+eq,4*cr0+eq + li r0,MAX_COPY_PREFETCH + li r11,4 + b 2b +#endif /* CONFIG_8xx */ /* * Atomic [test&set] exchange diff -urN linux-2.4.25/arch/ppc/kernel/ocp.c linux-2.4.26/arch/ppc/kernel/ocp.c --- linux-2.4.25/arch/ppc/kernel/ocp.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/arch/ppc/kernel/ocp.c 2004-04-14 06:05:27.000000000 -0700 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ //#define DBG(x) printk x #define DBG(x) +extern int mem_init_done; + extern struct ocp_def core_ocp[]; /* Static list of devices, provided by CPU core */ @@ -152,9 +155,9 @@ * @drv: pointer to statically defined ocp_driver structure * * The driver's probe() callback is called either recursively - * by this function or upon later call of ocp_init + * by this function or upon later call of ocp_driver_init * - * NOTE: Probe is called with ocp_drivers_sem heocp_find_deviceld, it shouldn't + * NOTE: Probe is called with ocp_drivers_sem held, it shouldn't * call ocp_register/unregister_driver on his own code path. * however, it _can_ call ocp_find_device(). * @@ -231,27 +234,15 @@ DBG(("ocp: ocp_unregister_driver(%s)... done.\n", drv->name)); } -/** - * ocp_find_device - Find a device by function & index - * @vendor: vendor ID of the device (or OCP_ANY_ID) - * @function: function code of the device (or OCP_ANY_ID) - * @idx: index of the device (or OCP_ANY_INDEX) - * - * This function allows a lookup of a given function by it's - * index, it's typically used to find the MAL or ZMII associated - * with an EMAC or similar horrors. - * You can pass vendor, though you usually want OCP_ANY_ID there... - */ -struct ocp_device * -ocp_find_device(unsigned int vendor, unsigned int function, int index) +/* Core of ocp_find_device(). Caller must hold ocp_devices_sem */ +static struct ocp_device * +__ocp_find_device(unsigned int vendor, unsigned int function, int index) { struct list_head *entry; struct ocp_device *dev, *found = NULL; - DBG(("ocp: ocp_find_device(vendor: %x, function: %x, index: %d)...\n", - vendor, function, index)); + DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index)); - down_read(&ocp_devices_sem); list_for_each(entry, &ocp_devices) { dev = list_entry(entry, struct ocp_device, link); if (vendor != OCP_ANY_ID && vendor != dev->def->vendor) @@ -263,9 +254,60 @@ found = dev; break; } + + DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)... done\n", vendor, function, index)); + + return found; +} + +/** + * ocp_find_device - Find a device by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows a lookup of a given function by it's + * index, it's typically used to find the MAL or ZMII associated + * with an EMAC or similar horrors. + * You can pass vendor, though you usually want OCP_ANY_ID there... + */ +struct ocp_device * +ocp_find_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + + down_read(&ocp_devices_sem); + dev = __ocp_find_device(vendor, function, index); up_read(&ocp_devices_sem); - DBG(("ocp: ocp_find_device(vendor: %x, function: %x, index: %d)... done.\n", + return dev; +} + +/** + * ocp_get_one_device - Find a def by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows a lookup of a given ocp_def by it's + * vendor, function, and index. The main purpose for is to + * allow modification of the def before binding to the driver + */ +struct ocp_def * +ocp_get_one_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + struct ocp_def *found = NULL; + + DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)...\n", + vendor, function, index)); + + dev = ocp_find_device(vendor, function, index); + + if (dev) + found = dev->def; + + DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)... done.\n", vendor, function, index)); return found; @@ -275,28 +317,80 @@ * ocp_add_one_device - Add a device * @def: static device definition structure * - * This function is solely meant to be called by ocp_init - * to add one device from the core static list to the - * device list + * This function adds a device definition to the + * device list. It may only be called before + * ocp_driver_init() and will return an error + * otherwise. */ -static void +int ocp_add_one_device(struct ocp_def *def) { struct ocp_device *dev; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index)); + + /* Can't be called after ocp driver init */ + if (ocp_inited) + return 1; + + if (mem_init_done) + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + else + dev = alloc_bootmem(sizeof(*dev)); + if (dev == NULL) - return; + return 1; memset(dev, 0, sizeof(*dev)); dev->def = def; dev->current_state = 4; sprintf(dev->name, "OCP device %04x:%04x:%04x", dev->def->vendor, dev->def->function, dev->def->index); + down_write(&ocp_devices_sem); list_add_tail(&dev->link, &ocp_devices); + up_write(&ocp_devices_sem); + + DBG(("ocp: ocp_add_one_device(vendor: %x, function: %x, index: %d)...done.\n", vendor, function, index)); + + return 0; +} + +/** + * ocp_remove_one_device - Remove a device by function & index + * @vendor: vendor ID of the device (or OCP_ANY_ID) + * @function: function code of the device (or OCP_ANY_ID) + * @idx: index of the device (or OCP_ANY_INDEX) + * + * This function allows removal of a given function by its + * index. It may only be called before ocp_driver_init() + * and will return an error otherwise. + */ +int +ocp_remove_one_device(unsigned int vendor, unsigned int function, int index) +{ + struct ocp_device *dev; + int rc = 0; + + DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index)); + + /* Can't be called after ocp driver init */ + if (ocp_inited) + return 1; + + down_write(&ocp_devices_sem); + dev = __ocp_find_device(vendor, function, index); + if (dev != NULL) + list_del((struct list_head *)dev); + else + rc = 1; + up_write(&ocp_devices_sem); + + DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)... done.\n", vendor, function, index)); + + return rc; } #ifdef CONFIG_PM -/* +/** * OCP Power management.. * * This needs to be done centralized, so that we power manage PCI @@ -400,35 +494,49 @@ #endif /* CONFIG_PM */ /** - * ocp_init - Init OCP device management + * ocp_early_init - Init OCP device management * - * This function is meant to be called once, and only once to initialize - * the OCP device management and build the list of devices. Note that - * it can actually be called at any time, it's perfectly legal to - * register drivers before ocp_init() is called + * This function builds the list of devices before setup_arch. + * This allows platform code to modify the device lists before + * they are bound to drivers (changes to paddr, removing devices + * etc) */ -int -ocp_init(void) +int __init +ocp_early_init(void) { struct ocp_def *def; - /* ocp_init is by default an initcall. If your arch requires this to - * be called earlier, then go on, ocp_init is non-static for that purpose, - * and can safely be called twice - */ - if (ocp_inited) - return 0; - ocp_inited = 1; - - DBG(("ocp: ocp_init()...\n")); + DBG(("ocp: ocp_early_init()...\n")); /* Fill the devices list */ - down_write(&ocp_devices_sem); for (def = core_ocp; def->vendor != OCP_VENDOR_INVALID; def++) ocp_add_one_device(def); - up_write(&ocp_devices_sem); - DBG(("ocp: ocp_init()... added...\n")); + DBG(("ocp: ocp_early_init()... done.\n")); + + return 0; +} + +/** + * ocp_driver_init - Init OCP device management + * + * This function is meant to be called once, and only once to initialize + * the OCP device management. Note that it can actually be called at any + * time, it's perfectly legal to register drivers before + * ocp_driver_init() is called + */ +int +ocp_driver_init(void) +{ + /* ocp_driver_init is by default an initcall. If your arch requires + * this to be called earlier, then go on, ocp_driver_init is + * non-static for that purpose, and can safely be called twice + */ + if (ocp_inited) + return 0; + ocp_inited = 1; + + DBG(("ocp: ocp_driver_init()...\n")); /* Call drivers probes */ down(&ocp_drivers_sem); @@ -439,12 +547,13 @@ pm_register(PM_SYS_DEV, 0, ocp_pm_callback); #endif - DBG(("ocp: ocp_init()... done.\n")); + DBG(("ocp: ocp_driver_init()... done.\n")); return 0; } -__initcall(ocp_init); +__initcall(ocp_driver_init); +EXPORT_SYMBOL(ocp_find_device); EXPORT_SYMBOL(ocp_register_driver); EXPORT_SYMBOL(ocp_unregister_driver); diff -urN linux-2.4.25/arch/ppc/kernel/ppc4xx_stbdma.c linux-2.4.26/arch/ppc/kernel/ppc4xx_stbdma.c --- linux-2.4.25/arch/ppc/kernel/ppc4xx_stbdma.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ppc4xx_stbdma.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,134 @@ +/* + * arch/ppc/kernel/ppc4xx_stbdma.c + * + * BRIEF MODULE DESCRIPTION + * IBM PPC4xx STBxxxx DMA Controller Functions + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * Armin Kuster + * + * Based on ppc4xx_dma.c by + * ppopov@mvista.com or source@mvista. + * + * 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. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +int +ppc4xx_clr_dma_status(unsigned int dmanr) +{ + unsigned int control; + ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; + + p_dma_ch->int_enable = 1; + + switch (dmanr) { + case 0: + control = DMA_CS0 | DMA_CH0_ERR | DMA_CT0; + break; + case 1: + control = DMA_CS1 | DMA_CH1_ERR | DMA_CT1; + break; + case 2: + control = DMA_CS2 | DMA_CH2_ERR | DMA_CT2; + break; + case 3: + control = DMA_CS3 | DMA_CH3_ERR | DMA_CT3; + break; + default: +#ifdef DEBUG_4xxDMA + printk("ppc4xx_clr_dma_status: bad channel: %d\n", dmanr); +#endif + return DMA_STATUS_BAD_CHANNEL; + } + mtdcr(DCRN_DMASR, control); + return DMA_STATUS_GOOD; +} + +/* + * Maps a given port to a one of the dma + * channels + */ +int +ppc4xx_map_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan) +{ + unsigned int map; + int connect_port_to_chan, select; + + ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; + + connect_port_to_chan = ((ocp_dma & 0x7)*4); + + select = ocp_dma >> 3; + switch (select) { + case 0: + map = mfdcr(DCRN_DMAS1); + map |= (connect_port_to_chan << dma_chan); /* */ + mtdcr(DCRN_DMAS1, map); + break; + case 1: + map = mfdcr(DCRN_DMAS2); + map |= (connect_port_to_chan << dma_chan); + mtdcr(DCRN_DMAS2, map); + break; + default: +#ifdef DEBUG_4xxDMA + printk("map_dma_port: bad channel: %d\n", dmanr); +#endif + return DMA_STATUS_BAD_CHANNEL; + } + return DMA_STATUS_GOOD; +} + +int +ppc4xx_disable_dma_port(unsigned int dmanr, unsigned int ocp_dma,short dma_chan) +{ + unsigned int map; + int connect_port_to_chan, select; + + ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; + + connect_port_to_chan = ((ocp_dma & 0x7)*4); + + select = ocp_dma >> 3; + switch (select) { + case 0: + map = mfdcr(DCRN_DMAS1); + map &= ~(connect_port_to_chan << dma_chan); /* */ + mtdcr(DCRN_DMAS1, map); + break; + case 1: + map = mfdcr(DCRN_DMAS2); + map &= ~(connect_port_to_chan << dma_chan); + mtdcr(DCRN_DMAS2, map); + break; + default: +#ifdef DEBUG_4xxDMA + printk("disable_dma_port: bad channel: %d\n", dmanr); +#endif + return DMA_STATUS_BAD_CHANNEL; + } + return DMA_STATUS_GOOD; +} + +EXPORT_SYMBOL(ppc4xx_disable_dma_port); +EXPORT_SYMBOL(ppc4xx_map_dma_port); +EXPORT_SYMBOL(ppc4xx_clr_dma_status); diff -urN linux-2.4.25/arch/ppc/kernel/ppc8260_pic.c linux-2.4.26/arch/ppc/kernel/ppc8260_pic.c --- linux-2.4.25/arch/ppc/kernel/ppc8260_pic.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/kernel/ppc8260_pic.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,128 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "ppc8260_pic.h" - -/* The 8260 internal interrupt controller. It is usually - * the only interrupt controller. - * There are two 32-bit registers (high/low) for up to 64 - * possible interrupts. - * - * Now, the fun starts.....Interrupt Numbers DO NOT MAP - * in a simple arithmetic fashion to mask or pending registers. - * That is, interrupt 4 does not map to bit position 4. - * We create two tables, indexed by vector number, to indicate - * which register to use and which bit in the register to use. - */ -static u_char irq_to_siureg[] = { - 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, - 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 -}; - -static u_char irq_to_siubit[] = { - 31, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, - 29, 30, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 31, - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 15, 14, 13, 12, 11, 10, 9, 8, - 7, 6, 5, 4, 3, 2, 1, 0 -}; - -static void m8260_mask_irq(unsigned int irq_nr) -{ - int bit, word; - volatile uint *simr; - - bit = irq_to_siubit[irq_nr]; - word = irq_to_siureg[irq_nr]; - - simr = &(immr->im_intctl.ic_simrh); - ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); - simr[word] = ppc_cached_irq_mask[word]; -} - -static void m8260_unmask_irq(unsigned int irq_nr) -{ - int bit, word; - volatile uint *simr; - - bit = irq_to_siubit[irq_nr]; - word = irq_to_siureg[irq_nr]; - - simr = &(immr->im_intctl.ic_simrh); - ppc_cached_irq_mask[word] |= (1 << (31 - bit)); - simr[word] = ppc_cached_irq_mask[word]; -} - -static void m8260_mask_and_ack(unsigned int irq_nr) -{ - int bit, word; - volatile uint *simr, *sipnr; - - bit = irq_to_siubit[irq_nr]; - word = irq_to_siureg[irq_nr]; - - simr = &(immr->im_intctl.ic_simrh); - sipnr = &(immr->im_intctl.ic_sipnrh); - ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); - simr[word] = ppc_cached_irq_mask[word]; - sipnr[word] = 1 << (31 - bit); -} - -static void m8260_end_irq(unsigned int irq_nr) -{ - int bit, word; - volatile uint *simr; - - if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - - bit = irq_to_siubit[irq_nr]; - word = irq_to_siureg[irq_nr]; - - simr = &(immr->im_intctl.ic_simrh); - ppc_cached_irq_mask[word] |= (1 << (31 - bit)); - simr[word] = ppc_cached_irq_mask[word]; - } -} - -struct hw_interrupt_type ppc8260_pic = { - " 8260 SIU ", - NULL, - NULL, - m8260_unmask_irq, - m8260_mask_irq, - m8260_mask_and_ack, - m8260_end_irq, - 0 -}; - -/* Return an interrupt vector or -1 if no interrupt is pending. */ -int -m8260_get_irq(struct pt_regs *regs) -{ - int irq; - unsigned long bits; - - /* For MPC8260, read the SIVEC register and shift the bits down - * to get the irq number. */ - bits = immr->im_intctl.ic_sivec; - irq = bits >> 26; - - if (irq == 0) /* 0 --> no irq is pending */ - irq = -1; - - return irq; -} - diff -urN linux-2.4.25/arch/ppc/kernel/ppc8260_pic.h linux-2.4.26/arch/ppc/kernel/ppc8260_pic.h --- linux-2.4.25/arch/ppc/kernel/ppc8260_pic.h 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/kernel/ppc8260_pic.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,13 +0,0 @@ -#ifndef _PPC_KERNEL_PPC8260_H -#define _PPC_KERNEL_PPC8260_H - -#include - -extern struct hw_interrupt_type ppc8260_pic; - -void m8260_pic_init(void); -void m8260_do_IRQ(struct pt_regs *regs, - int cpu); -int m8260_get_irq(struct pt_regs *regs); - -#endif /* _PPC_KERNEL_PPC8260_H */ diff -urN linux-2.4.25/arch/ppc/kernel/ppc_ksyms.c linux-2.4.26/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.25/arch/ppc/kernel/ppc_ksyms.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/ppc_ksyms.c 2004-04-14 06:05:27.000000000 -0700 @@ -161,6 +161,8 @@ EXPORT_SYMBOL(_outsl_ns); EXPORT_SYMBOL(iopa); EXPORT_SYMBOL(mm_ptov); +EXPORT_SYMBOL(vmalloc_start); +EXPORT_SYMBOL(ioremap_bot); EXPORT_SYMBOL(ioremap); #ifdef CONFIG_PTE_64BIT EXPORT_SYMBOL(ioremap64); diff -urN linux-2.4.25/arch/ppc/kernel/setup.c linux-2.4.26/arch/ppc/kernel/setup.c --- linux-2.4.25/arch/ppc/kernel/setup.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/setup.c 2004-04-14 06:05:27.000000000 -0700 @@ -603,6 +603,12 @@ do_init_bootmem(); if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); +#ifdef CONFIG_PPC_OCP + /* Initialize OCP device list */ + ocp_early_init(); + if ( ppc_md.progress ) ppc_md.progress("setup_arch: ocp_early_init", 0x3eab); +#endif + ppc_md.setup_arch(); if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); diff -urN linux-2.4.25/arch/ppc/kernel/traps.c linux-2.4.26/arch/ppc/kernel/traps.c --- linux-2.4.25/arch/ppc/kernel/traps.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/ppc/kernel/traps.c 2004-04-14 06:05:27.000000000 -0700 @@ -212,15 +212,44 @@ if (check_io_access(regs)) return; -#ifdef CONFIG_4xx +#if defined(CONFIG_4xx) && !defined(CONFIG_440A) if (reason & ESR_IMCP) { printk("Instruction"); mtspr(SPRN_ESR, reason & ~ESR_IMCP); } else printk("Data"); printk(" machine check in kernel mode.\n"); - -#else /* !CONFIG_4xx */ +#elif defined(CONFIG_440A) + printk("Machine check in kernel mode.\n"); + if (reason & ESR_IMCP){ + printk("Instruction Synchronous Machine Check exception\n"); + mtspr(SPRN_ESR, reason & ~ESR_IMCP); + } + else { + u32 mcsr = mfspr(SPRN_MCSR); + if (mcsr & MCSR_IB) + printk("Instruction Read PLB Error\n"); + if (mcsr & MCSR_DRB) + printk("Data Read PLB Error\n"); + if (mcsr & MCSR_DWB) + printk("Data Write PLB Error\n"); + if (mcsr & MCSR_TLBP) + printk("TLB Parity Error\n"); + if (mcsr & MCSR_ICP){ + flush_instruction_cache(); + printk("I-Cache Parity Error\n"); + } + if (mcsr & MCSR_DCSP) + printk("D-Cache Search Parity Error\n"); + if (mcsr & MCSR_DCFP) + printk("D-Cache Flush Parity Error\n"); + if (mcsr & MCSR_IMPE) + printk("Machine Check exception is imprecise\n"); + + /* Clear MCSR */ + mtspr(SPRN_MCSR, mcsr); + } +#else /* !CONFIG_4xx && !CONFIG_E500 */ printk("Machine check in kernel mode.\n"); printk("Caused by (from SRR1=%lx): ", reason); switch (reason & 0x601F0000) { diff -urN linux-2.4.25/arch/ppc/lib/string.S linux-2.4.26/arch/ppc/lib/string.S --- linux-2.4.25/arch/ppc/lib/string.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/arch/ppc/lib/string.S 2004-04-14 06:05:27.000000000 -0700 @@ -62,13 +62,14 @@ .text .text + .stabs "arch/ppc/lib/",N_SO,0,0,0f + .stabs "string.S",N_SO,0,0,0f CACHELINE_BYTES = L1_CACHE_LINE_SIZE LG_CACHELINE_BYTES = LG_L1_CACHE_LINE_SIZE CACHELINE_MASK = (L1_CACHE_LINE_SIZE-1) - .globl strcpy -strcpy: +_GLOBAL(strcpy) addi r5,r3,-1 addi r4,r4,-1 1: lbzu r0,1(r4) @@ -79,8 +80,7 @@ /* This clears out any unused part of the destination buffer, just as the libc version does. -- paulus */ - .globl strncpy -strncpy: +_GLOBAL(strncpy) cmpwi 0,r5,0 beqlr mtctr r5 @@ -98,8 +98,7 @@ bdnz 2b blr - .globl strcat -strcat: +_GLOBAL(strcat) addi r5,r3,-1 addi r4,r4,-1 1: lbzu r0,1(r5) @@ -112,8 +111,7 @@ bne 1b blr - .globl strcmp -strcmp: +_GLOBAL(strcmp) addi r5,r3,-1 addi r4,r4,-1 1: lbzu r3,1(r5) @@ -124,8 +122,7 @@ beq 1b blr - .globl strlen -strlen: +_GLOBAL(strlen) addi r4,r3,-1 1: lbzu r0,1(r4) cmpwi 0,r0,0 @@ -138,8 +135,7 @@ * to set them to zero. This requires that the destination * area is cacheable. -- paulus */ - .globl cacheable_memzero -cacheable_memzero: +_GLOBAL(cacheable_memzero) mr r5,r4 li r4,0 addi r6,r3,-4 @@ -189,8 +185,7 @@ bdnz 8b blr - .globl memset -memset: +_GLOBAL(memset) rlwimi r4,r4,8,16,23 rlwimi r4,r4,16,0,15 addi r6,r3,-4 @@ -215,8 +210,7 @@ bdnz 8b blr - .globl bcopy -bcopy: +_GLOBAL(bcopy) mr r6,r3 mr r3,r4 mr r4,r6 @@ -229,8 +223,7 @@ * We only use this version if the source and dest don't overlap. * -- paulus. */ - .global cacheable_memcpy -cacheable_memcpy: +_GLOBAL(cacheable_memcpy) add r7,r3,r5 /* test if the src & dst overlap */ add r8,r4,r5 cmplw 0,r4,r7 @@ -304,14 +297,12 @@ bdnz 40b 65: blr - .globl memmove -memmove: +_GLOBAL(memmove) cmplw 0,r3,r4 bgt backwards_memcpy /* fall through */ - .globl memcpy -memcpy: +_GLOBAL(memcpy) srwi. r7,r5,3 addi r6,r3,-4 addi r4,r4,-4 @@ -352,8 +343,7 @@ mtctr r7 b 1b - .globl backwards_memcpy -backwards_memcpy: +_GLOBAL(backwards_memcpy) rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ add r6,r3,r5 add r4,r4,r5 @@ -389,8 +379,7 @@ mtctr r7 b 1b - .globl memcmp -memcmp: +_GLOBAL(memcmp) cmpwi 0,r5,0 ble- 2f mtctr r5 @@ -404,8 +393,7 @@ 2: li r3,0 blr - .global memchr -memchr: +_GLOBAL(memchr) cmpwi 0,r5,0 ble- 2f mtctr r5 @@ -417,8 +405,7 @@ 2: li r3,0 blr - .globl __copy_tofrom_user -__copy_tofrom_user: +_GLOBAL(__copy_tofrom_user) addi r4,r4,-4 addi r6,r3,-4 neg r0,r3 @@ -443,48 +430,57 @@ 73: stwu r9,4(r6) bdnz 72b + .section __ex_table,"a" + .align 2 + .long 70b,100f + .long 71b,101f + .long 72b,102f + .long 73b,103f + .text + 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ clrlwi r5,r5,32-LG_CACHELINE_BYTES li r11,4 beq 63f -#if !defined(CONFIG_8xx) +#ifdef CONFIG_8xx + /* Don't use prefetch on 8xx */ + mtctr r0 +53: COPY_16_BYTES_WITHEX(0) + bdnz 53b + +#else /* not CONFIG_8xx */ /* Here we decide how far ahead to prefetch the source */ + li r3,4 + cmpwi r0,1 + li r7,0 + ble 114f + li r7,1 #if MAX_COPY_PREFETCH > 1 /* Heuristically, for large transfers we prefetch MAX_COPY_PREFETCH cachelines ahead. For small transfers we prefetch 1 cacheline ahead. */ cmpwi r0,MAX_COPY_PREFETCH - li r7,1 - li r3,4 - ble 111f + ble 112f li r7,MAX_COPY_PREFETCH -111: mtctr r7 -112: dcbt r3,r4 +112: mtctr r7 +111: dcbt r3,r4 addi r3,r3,CACHELINE_BYTES - bdnz 112b -#else /* MAX_COPY_PREFETCH == 1 */ - li r3,CACHELINE_BYTES + 4 - dcbt r11,r4 -#endif /* MAX_COPY_PREFETCH */ -#endif /* CONFIG_8xx */ - - mtctr r0 -53: -#if !defined(CONFIG_8xx) + bdnz 111b +#else dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES +#endif /* MAX_COPY_PREFETCH > 1 */ + +114: subf r8,r7,r0 + mr r0,r7 + mtctr r8 + +53: dcbt r3,r4 54: dcbz r11,r6 -#endif -/* had to move these to keep extable in order */ .section __ex_table,"a" .align 2 - .long 70b,100f - .long 71b,101f - .long 72b,102f - .long 73b,103f -#if !defined(CONFIG_8xx) .long 54b,105f -#endif .text /* the main body of the cacheline loop */ COPY_16_BYTES_WITHEX(0) @@ -502,6 +498,11 @@ #endif #endif bdnz 53b + cmpwi r0,0 + li r3,4 + li r7,0 + bne 114b +#endif /* CONFIG_8xx */ 63: srwi. r0,r5,2 mtctr r0 @@ -624,8 +625,7 @@ .long 114b,120b .text - .globl __clear_user -__clear_user: +_GLOBAL(__clear_user) addi r6,r3,-4 li r3,0 li r5,0 @@ -668,8 +668,7 @@ .long 8b,92b .text - .globl __strncpy_from_user -__strncpy_from_user: +_GLOBAL(__strncpy_from_user) addi r6,r3,-1 addi r4,r4,-1 cmpwi 0,r5,0 @@ -692,8 +691,7 @@ .text /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ - .globl __strnlen_user -__strnlen_user: +_GLOBAL(__strnlen_user) addi r7,r3,-1 subf r6,r7,r5 /* top+1 - str */ cmplw 0,r4,r6 diff -urN linux-2.4.25/arch/ppc/platforms/Makefile linux-2.4.26/arch/ppc/platforms/Makefile --- linux-2.4.25/arch/ppc/platforms/Makefile 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/Makefile 2004-04-14 06:05:27.000000000 -0700 @@ -33,6 +33,9 @@ obj-$(CONFIG_440GX) += ibm440gx.o obj-$(CONFIG_CPCI405) += cpci405.o +obj-$(CONFIG_EP405) += ep405.o +obj-$(CONFIG_REDWOOD_5) += redwood5.o ibmstb4.o +obj-$(CONFIG_REDWOOD_6) += redwood6.o ibmstbx25.o obj-$(CONFIG_EBONY) += ebony.o obj-$(CONFIG_OCOTEA) += ocotea.o obj-$(CONFIG_WALNUT) += walnut.o diff -urN linux-2.4.25/arch/ppc/platforms/ebony.c linux-2.4.26/arch/ppc/platforms/ebony.c --- linux-2.4.25/arch/ppc/platforms/ebony.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ebony.c 2004-04-14 06:05:27.000000000 -0700 @@ -234,7 +234,7 @@ /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); - PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); + PCIX_WRITEL(0x80000007, PCIX0_PIM0SA); eieio(); } @@ -335,7 +335,7 @@ ebony_setup_arch(void) { unsigned char * vpd_base; - struct ibm440gp_clocks clocks; + struct ibm44x_clocks clocks; bd_t *bip = (bd_t *) __res; #if !defined(CONFIG_BDI_SWITCH) diff -urN linux-2.4.25/arch/ppc/platforms/ep405.c linux-2.4.26/arch/ppc/platforms/ep405.c --- linux-2.4.25/arch/ppc/platforms/ep405.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ep405.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,196 @@ +/* + * BK Id: %F% %I% %G% %U% %#% + * + * Copyright 2001 MontaVista Software Inc. + * + * + * Not much needed for the Embedded Planet 405gp board + * + * History: 11/09/2001 - armin + * added board_init to add in additional instuctions needed during platfrom_init + * cleaned up map_irq. + * + * 1/22/2002 - Armin + * converted pci to ocp + * + * Please read the COPYING file for all license details. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +u8 *ep405_bcsr; +u8 *ep405_nvram; + +static struct { + u8 cpld_xirq_select; + int pci_idsel; + int irq; +} ep405_devtable[] = { +#ifdef CONFIG_EP405PC + {0x07, 0x0E, 25}, /* EP405PC: USB */ +#endif +}; +#define EP405_DEVTABLE_SIZE (sizeof(ep405_devtable)/sizeof(ep405_devtable[0])) + +int __init +ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + int i; + + /* AFAICT this is only called a few times during PCI setup, so + performance is not critical */ + for (i = 0; i < EP405_DEVTABLE_SIZE; i++) { + if (idsel == ep405_devtable[i].pci_idsel) + return ep405_devtable[i].irq; + } + return -1; +}; + +void __init +board_setup_arch(void) +{ + bd_t *bip = (bd_t *) __res; + + if (bip->bi_nvramsize == 512*1024) { + /* FIXME: we should properly handle NVRTCs of different sizes */ + TODC_INIT(TODC_TYPE_DS1557, ep405_nvram, ep405_nvram, ep405_nvram, 8); + } +} + +#ifdef CONFIG_PCI +void __init +bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip) +{ + unsigned int bar_response, bar; + /* + * Expected PCI mapping: + * + * PLB addr PCI memory addr + * --------------------- --------------------- + * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff + * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff + * + * PLB addr PCI io addr + * --------------------- --------------------- + * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000 + * + */ + + /* Disable region zero first */ + out_le32((void *) &(pcip->pmm[0].ma), 0x00000000); + /* PLB starting addr, PCI: 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].la), 0x80000000); + /* PCI start addr, 0x80000000 */ + out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE); + /* 512MB range of PLB to PCI */ + out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000); + /* Enable no pre-fetch, enable region */ + out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff - + (PPC405_PCI_UPPER_MEM - + PPC405_PCI_MEM_BASE)) | 0x01)); + + /* Disable region one */ + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[1].la), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[1].ma), 0x00000000); + out_le32((void *) &(pcip->ptm1ms), 0x00000000); + + /* Disable region two */ + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->pmm[2].la), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000); + out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000); + out_le32((void *) &(pcip->pmm[2].ma), 0x00000000); + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Configure PTM (PCI->PLB) region 1 */ + out_le32((void *) &(pcip->ptm1la), 0x00000000); /* PLB base address */ + /* Disable PTM region 2 */ + out_le32((void *) &(pcip->ptm2ms), 0x00000000); + + /* Zero config bars */ + for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) { + early_write_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + 0x00000000); + early_read_config_dword(hose, hose->first_busno, + PCI_FUNC(hose->first_busno), bar, + &bar_response); + DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n", + hose->first_busno, PCI_SLOT(hose->first_busno), + PCI_FUNC(hose->first_busno), bar, bar_response); + } + /* end work arround */ +} +#endif + +void __init +board_io_mapping(void) +{ + bd_t *bip = (bd_t *) __res; + + ep405_bcsr = ioremap(EP405_BCSR_PADDR, EP405_BCSR_SIZE); + + if (bip->bi_nvramsize > 0) { + ep405_nvram = ioremap(EP405_NVRAM_PADDR, bip->bi_nvramsize); + } +} + +void __init +board_setup_irq(void) +{ + int i; + + /* Workaround for a bug in the firmware it incorrectly sets + the IRQ polarities for XIRQ0 and XIRQ1 */ + mtdcr(DCRN_UIC_PR(DCRN_UIC0_BASE), 0xffffff80); /* set the polarity */ + mtdcr(DCRN_UIC_SR(DCRN_UIC0_BASE), 0x00000060); /* clear bogus interrupts */ + + /* Activate the XIRQs from the CPLD */ + writeb(0xf0, ep405_bcsr+10); + + /* Set up IRQ routing */ + for (i = 0; i < EP405_DEVTABLE_SIZE; i++) { + if ( (ep405_devtable[i].irq >= 25) + && (ep405_devtable[i].irq) <= 31) { + writeb(ep405_devtable[i].cpld_xirq_select, ep405_bcsr+5); + writeb(ep405_devtable[i].irq - 25, ep405_bcsr+6); + } + } +} + +void __init +board_init(void) +{ + bd_t *bip = (bd_t *) __res; + +#ifdef CONFIG_PPC_RTC + /* FIXME: we should be able to access the NVRAM even if PPC_RTC is not configured */ + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; + + if (bip->bi_nvramsize == 512*1024) { + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + } else { + printk("EP405: NVRTC size is not 512k (not a DS1557). Not sure what to do with it\n"); + } + +#endif +} diff -urN linux-2.4.25/arch/ppc/platforms/ep405.h linux-2.4.26/arch/ppc/platforms/ep405.h --- linux-2.4.25/arch/ppc/platforms/ep405.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ep405.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright 2000 MontaVista Software Inc. + * http://www.mvista.com + * + * + * Embedded Planet 405GP board + * http://www.embeddedplanet.com + * + * Please read the COPYING file for all license details. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_EP405_H__ +#define __ASM_EP405_H__ + +/* We have a 405GP core */ +#include + +#ifndef __ASSEMBLY__ +typedef struct board_info { + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ + unsigned int bi_nvramsize; /* Size of the NVRAM/RTC */ + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + int bi_iic_fast[1]; /* Use fast i2c mode */ +} bd_t; + +/* Some 4xx parts use a different timebase frequency from the internal clock. +*/ +#define bi_tbfreq bi_intfreq + +extern u8 *ep405_bcsr; +extern u8 *ep405_nvram; + +/* Map for the BCSR and NVRAM space */ +#define EP405_BCSR_PADDR ((uint)0xf4000000) +#define EP405_BCSR_SIZE ((uint)16) +#define EP405_NVRAM_PADDR ((uint)0xf4200000) + +/* serial defines */ +#define BASE_BAUD 399193 + +#define PPC4xx_MACHINE_NAME "Embedded Planet 405GP" + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_EP405_H__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/est8260.h linux-2.4.26/arch/ppc/platforms/est8260.h --- linux-2.4.25/arch/ppc/platforms/est8260.h 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.26/arch/ppc/platforms/est8260.h 2004-04-14 06:05:27.000000000 -0700 @@ -4,7 +4,7 @@ * the configuration SCMR and the Power-On-Reset word. */ -#define IMAP_ADDR ((uint)0xf0000000) +#define CPM_MAP_ADDR ((uint)0xf0000000) /* A Board Information structure that is given to a program when diff -urN linux-2.4.25/arch/ppc/platforms/ibmstb4.c linux-2.4.26/arch/ppc/platforms/ibmstb4.c --- linux-2.4.25/arch/ppc/platforms/ibmstb4.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ibmstb4.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,101 @@ +/* + * + * Copyright 2000-2001 MontaVista Software Inc. + * Completed implementation. + * Current maintainer + * Armin Kuster akuster@mvista.com + * + * Module name: ibmstb4.c + * + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * History: 12/26/2001 - armin + * initial release + * + * : 05/05/02 - Armin + * replaced all const strcuts with new core_ocp + * + * : 07/07/02 - Armin + * added OCP_IRQ_MUL to define EMAC + * and added PM register + * + */ + +#include +#include +#include + +struct ocp_def core_ocp[] __initdata = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = UART2_IO_BASE, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC0_BASE, + .irq = IIC0_IRQ, + .pm = IBM_CPM_IIC0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC1_BASE, + .irq = IIC1_IRQ, + .pm = IBM_CPM_IIC1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = GPIO0_BASE, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IDE, + .paddr = IDE0_BASE, + .irq = IDE0_IRQ, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_USB, + .paddr = USB0_BASE, + .irq = USB0_IRQ, + .pm = OCP_CPM_NA, + }, + { .vendor = OCP_VENDOR_INVALID, + } +}; diff -urN linux-2.4.25/arch/ppc/platforms/ibmstb4.h linux-2.4.26/arch/ppc/platforms/ibmstb4.h --- linux-2.4.25/arch/ppc/platforms/ibmstb4.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ibmstb4.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,285 @@ +/* + * ibmstb4.h + * + * This was dirived from the ibm405gp.h and other previus works in ppc4xx.h + * + * Current maintainer + * Armin Kuster akuster@mvista.com + * DEC, 2001 + * + * + * Copyright 2001 MontaVista Softare 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * Version 1.0 (01/10/10) - A. Kuster + * Initial version + * + * Version 1.1 02/01/17 - A. Kuster + * moved common offsets to ibm405.h + * + * Version 1.2 02/22/02 - A. Kuster + * Added UIC and + * Added early serial boot #define support - David G. + * fixed __BOOTER__ + * + * Version 1.3 03/29/02 - Armin + * Added i2c & usb ocp support + * + * Version 1.4 04/30/02 - Armin + * Added IIC_PORT_DFNS macros + * Version 1.5 - 05/05/02 _ armin + * removed IIC_PORT now using core_ocp[] + * + * Version 1.6 07/22/02 - Armin + * added default power managment setting + * + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBMSTB4_H__ +#define __ASM_IBMSTB4_H__ + +#include +#include + +/* serial port defines */ +#define STB04xxx_IO_BASE ((uint)0xe0000000) +#define PPC4xx_PCI_IO_ADDR STB04xxx_IO_BASE +#define PPC4xx_ONB_IO_PADDR STB04xxx_IO_BASE +#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000) +#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024) + +/* + * map STB04xxx internal i/o address (0x400x00xx) to an address + * which is below the 2GB limit... + * + * 4000 000x uart1 -> 0xe000 000x + * 4001 00xx ppu + * 4002 00xx smart card + * 4003 000x iic + * 4004 000x uart0 + * 4005 0xxx timer + * 4006 00xx gpio + * 4007 00xx smart card + * 400b 000x iic + * 400c 000x scp + * 400d 000x modem + * 400e 000x uart2 +*/ +#define STB04xxx_MAP_IO_ADDR(a) (((uint)(a)) + (STB04xxx_IO_BASE - 0x40000000)) + +#define RS_TABLE_SIZE 3 +#define UART0_INT 20 + +#ifdef __BOOTER__ +#define UART0_IO_BASE 0x40040000 +#else +#define UART0_IO_BASE 0xe0040000 +#endif + +#define UART1_INT 21 + +#ifdef __BOOTER__ +#define UART1_IO_BASE 0x40000000 +#else +#define UART1_IO_BASE 0xe0000000 +#endif + +#define UART2_INT 31 +#ifdef __BOOTER__ +#define UART2_IO_BASE 0x400e0000 +#else +#define UART2_IO_BASE 0xe00e0000 +#endif + +#define IDE0_BASE 0x400F0000 +#define IDE0_SIZE 0x200 +#define IDE0_IRQ 25 +#define IIC0_BASE 0x40030000 +#define IIC1_BASE 0x400b0000 +#define OPB0_BASE 0x40000000 +#define GPIO0_BASE 0x40060000 + +#define USB0_IRQ 18 +#define USB0_BASE STB04xxx_MAP_IO_ADDR(0x40010000) +#define USB0_EXTENT 4096 + +#define IIC_NUMS 2 +#define UART_NUMS 3 +#define IIC0_IRQ 9 +#define IIC1_IRQ 10 +#define IIC_OWN 0x55 +#define IIC_CLOCK 50 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS2) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(2) \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */ +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_PLB0_BASE 0x054 +#define DCRN_PLB1_BASE 0x064 +#define DCRN_POB0_BASE 0x0B0 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_UIC0_BASE 0x040 +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRN_CIC_BASE 0x030 +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_EBIMC_BASE 0x070 +#define DCRN_DCRX_BASE 0x020 +#define DCRN_CPMFR_BASE 0x102 +#define DCRN_SCCR_BASE 0x120 +#define UIC0 DCRN_UIC0_BASE + +#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */ +#define IBM_CPM_USB0 0x40000000 /* IEEE-1284 */ +#define IBM_CPM_IIC1 0x20000000 /* IIC 1 interface */ +#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */ +#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */ +#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */ +#define IBM_CPM_SDRAM1 0x02000000 /* SDRAM 1 memory controller */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_DMA1 0x00800000 /* reserved */ +#define IBM_CPM_XPT1 0x00400000 /* reserved */ +#define IBM_CPM_XPT2 0x00200000 /* reserved */ +#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */ +#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */ +#define IBM_CPM_EPI 0x00040000 /* DCR Extension */ +#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */ +#define IBM_CPM_VID 0x00010000 /* reserved */ +#define IBM_CPM_SC1 0x00008000 /* Smart Card 1 */ +#define IBM_CPM_USBSDRA 0x00004000 /* SDRAM 0 memory controller */ +#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */ +#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */ +#define IBM_CPM_GPT 0x00000800 /* GPTPWM */ +#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */ +#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */ +#define IBM_CPM_TMRCLK 0x00000100 /* CPU timers */ +#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */ +#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */ +#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */ +#define IBM_CPM_UART2 0x00000008 /* Serial Control Port */ +#define IBM_CPM_DDIO 0x00000004 /* Descrambler */ +#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_SDRAM1 \ + | IBM_CPM_DMA | IBM_CPM_DMA1 | IBM_CPM_CBS \ + | IBM_CPM_USBSDRA | IBM_CPM_XPT0 | IBM_CPM_TMRCLK \ + | IBM_CPM_XPT27 | IBM_CPM_UIC ) + +#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */ +#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */ +/* DCRN_BESR */ +#define BESR_DSES 0x80000000 /* Data-Side Error Status */ +#define BESR_DMES 0x40000000 /* DMA Error Status */ +#define BESR_RWS 0x20000000 /* Read/Write Status */ +#define BESR_ETMASK 0x1C000000 /* Error Type */ +#define ET_PROT 0 +#define ET_PARITY 1 +#define ET_NCFG 2 +#define ET_BUSERR 4 +#define ET_BUSTO 6 + +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ +#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */ + +#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */ +#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */ +#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */ +#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */ +#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */ +#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */ +#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */ +#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */ +#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */ + +#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */ +#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */ +#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */ +#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */ +#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */ +#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */ +#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */ +#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */ + +#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */ +#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */ +#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */ +#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */ +#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */ +#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */ +#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */ +#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */ +#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */ +#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */ +#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */ +#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */ +#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */ +#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */ +#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */ +#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */ +#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */ +#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */ +#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */ + +#include + +#endif /* __ASM_IBMSTB4_H__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/ibmstbx25.c linux-2.4.26/arch/ppc/platforms/ibmstbx25.c --- linux-2.4.25/arch/ppc/platforms/ibmstbx25.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ibmstbx25.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,77 @@ +/* + * + * Copyright 2000-2002 MontaVista Software Inc. + * Completed implementation. + * Current maintainer + * Armin Kuster akuster@mvista.com + * + * Module name: ibmstbx25.c + * + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * History: July 10, 2002 - armin + * initial release + * + * + */ + +#include +#include +#include + +struct ocp_def core_ocp[] __initdata = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = UART0_IO_BASE, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = UART1_IO_BASE, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = UART2_IO_BASE, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .paddr = IIC0_BASE, + .irq = IIC0_IRQ, + .pm = IBM_CPM_IIC0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .paddr = GPIO0_BASE, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; diff -urN linux-2.4.25/arch/ppc/platforms/ibmstbx25.h linux-2.4.26/arch/ppc/platforms/ibmstbx25.h --- linux-2.4.25/arch/ppc/platforms/ibmstbx25.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ibmstbx25.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,287 @@ +/* + * ibmstbx25.h + * + * Current maintainer + * Armin Kuster akuster@mvista.com + * July, 2002 + * + * + * Copyright 2002 MontaVista Softare 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * Version 1.0 July 10, 2002 - A. Kuster + * Initial version + * + * Version 1.1 July 24, 02 - Armin + * added Power Managment defines + * + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_IBMSTBX25_H__ +#define __ASM_IBMSTBX25_H__ + +#include +#include + +/* serial port defines */ +#define STBx25xx_IO_BASE ((uint)0xe0000000) +#define PPC4xx_ONB_IO_PADDR STBx25xx_IO_BASE +#define PPC4xx_ONB_IO_VADDR ((uint)0xe0000000) +#define PPC4xx_ONB_IO_SIZE ((uint)14*64*1024) + +/* + * map STBxxxx internal i/o address (0x400x00xx) to an address + * which is below the 2GB limit... + * + * 4000 000x uart1 -> 0xe000 000x + * 4001 00xx uart2 + * 4002 00xx smart card + * 4003 000x iic + * 4004 000x uart0 + * 4005 0xxx timer + * 4006 00xx gpio + * 4007 00xx smart card + * 400b 000x iic + * 400c 000x scp + * 400d 000x modem + * 400e 000x uart2 +*/ +#define STBx25xx_MAP_IO_ADDR(a) (((uint)(a)) + (STBx25xx_IO_BASE - 0x40000000)) + +#define RS_TABLE_SIZE 3 + +#ifdef __BOOTER__ +#define UART1_IO_BASE 0x40000000 +#define UART2_IO_BASE 0x40010000 +#else +#define UART1_IO_BASE 0xe0000000 +#define UART2_IO_BASE 0xe0010000 +#endif +#define SC0_BASE 0x40020000 /* smart card #0 */ +#define IIC0_BASE 0x40030000 +#ifdef __BOOTER__ +#define UART0_IO_BASE 0x40040000 +#else +#define UART0_IO_BASE 0xe0040000 +#endif +#define SCC0_BASE 0x40040000 /* Serial 0 controller IrdA */ +#define GPT0_BASE 0x40050000 /* General purpose timers */ +#define OPB0_BASE 0x40000000 +#define GPIO0_BASE 0x40060000 +#define SC0_base 0x40070000 /* smart card #1 */ +#define SCP0_base 0x400C0000 /* Serial Controller Port */ +#define SSP0_BASE 0x400D0000 /* Sync serial port */ + +#define REDWOOD_IDE_CMD 0xf0100000 +#define REDWOOD_IDE_CTRL 0xf1100000 + +#define RTCFPC_IRQ 0 +#define XPORT_IRQ 1 +#define AUD_IRQ 2 +#define AID_IRQ 3 +#define DMA0 4 +#define DMA1_IRQ 5 +#define DMA2_IRQ 6 +#define DMA3_IRQ 7 +#define SC0_IRQ 8 +#define IIC0_IRQ 9 +#define IIR0_IRQ 10 +#define GPT0_IRQ 11 +#define GPT1_IRQ 12 +#define SCP0_IRQ 13 +#define SSP0_IRQ 14 +#define GPT2_IRQ 15 /* count down timer */ +#define SC1_IRQ 16 +/* IRQ 17 - 19 external */ +#define UART0_INT 20 +#define UART1_INT 21 +#define UART2_INT 22 +#define XPTDMA_IRQ 23 +#define DCRIDE_IRQ 24 +/* IRQ 25 - 30 external */ +#define IDE0_IRQ 26 + +#define IIC_NUMS 1 +#define UART_NUMS 3 +#define IIC_OWN 0x55 +#define IIC_CLOCK 50 + +#define BD_EMAC_ADDR(e,i) bi_enetaddr[i] + +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (u8 *)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#if defined(CONFIG_UART0_TTYS0) +#define SERIAL_DEBUG_IO_BASE UART0_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS1) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(1) \ + STD_UART_OP(0) \ + STD_UART_OP(2) +#endif + +#if defined(CONFIG_UART0_TTYS2) +#define SERIAL_DEBUG_IO_BASE UART2_IO_BASE +#define SERIAL_PORT_DFNS \ + STD_UART_OP(2) \ + STD_UART_OP(0) \ + STD_UART_OP(1) +#endif + +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRNCAP_DMA_CC 1 /* have DMA chained count capability */ +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_PLB0_BASE 0x054 +#define DCRN_PLB1_BASE 0x064 +#define DCRN_POB0_BASE 0x0B0 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_UIC0_BASE 0x040 +#define DCRN_BE_BASE 0x090 +#define DCRN_DMA0_BASE 0x0C0 +#define DCRN_DMA1_BASE 0x0C8 +#define DCRN_DMA2_BASE 0x0D0 +#define DCRN_DMA3_BASE 0x0D8 +#define DCRN_CIC_BASE 0x030 +#define DCRN_DMASR_BASE 0x0E0 +#define DCRN_EBIMC_BASE 0x070 +#define DCRN_DCRX_BASE 0x020 +#define DCRN_CPMFR_BASE 0x102 +#define DCRN_SCCR_BASE 0x120 +#define DCRN_RTCFP_BASE 0x310 + +#define UIC0 DCRN_UIC0_BASE + +#define IBM_CPM_IIC0 0x80000000 /* IIC 0 interface */ +#define IBM_CPM_CPU 0x10000000 /* PPC405B3 clock control */ +#define IBM_CPM_AUD 0x08000000 /* Audio Decoder */ +#define IBM_CPM_EBIU 0x04000000 /* External Bus Interface Unit */ +#define IBM_CPM_IRR 0x02000000 /* Infrared reciever */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_UART2 0x00200000 /* Serial Control Port */ +#define IBM_CPM_UART1 0x00100000 /* Serial 1 / Infrared */ +#define IBM_CPM_UART0 0x00080000 /* Serial 0 / 16550 */ +#define IBM_PM_DCRIDE 0x00040000 /* DCR timeout & IDE line Mode clock */ +#define IBM_CPM_SC0 0x00020000 /* Smart Card 0 */ +#define IBM_CPM_VID 0x00010000 /* reserved */ +#define IBM_CPM_SC1 0x00008000 /* Smart Card 0 */ +#define IBM_CPM_XPT0 0x00002000 /* Transport - 54 Mhz */ +#define IBM_CPM_CBS 0x00001000 /* Cross Bar Switch */ +#define IBM_CPM_GPT 0x00000800 /* GPTPWM */ +#define IBM_CPM_GPIO0 0x00000400 /* General Purpose IO 0 */ +#define IBM_CPM_DENC 0x00000200 /* Digital video Encoder */ +#define IBM_CPM_C405T 0x00000100 /* CPU timers */ +#define IBM_CPM_XPT27 0x00000080 /* Transport - 27 Mhz */ +#define IBM_CPM_UIC 0x00000040 /* Universal Interrupt Controller */ +#define IBM_CPM_RTCFPC 0x00000020 /* Realtime clock and front panel */ +#define IBM_CPM_SSP 0x00000010 /* Modem Serial Interface (SSP) */ +#define IBM_CPM_VID2 0x00000002 /* Video Decoder clock domain 2 */ +#define DFLT_IBM4xx_PM ~(IBM_CPM_CPU | IBM_CPM_EBIU | IBM_CPM_DMA \ + | IBM_CPM_CBS | IBM_CPM_XPT0 | IBM_CPM_C405T \ + | IBM_CPM_XPT27 | IBM_CPM_UIC) + +#define DCRN_BEAR (DCRN_BE_BASE + 0x0) /* Bus Error Address Register */ +#define DCRN_BESR (DCRN_BE_BASE + 0x1) /* Bus Error Syndrome Register */ +/* DCRN_BESR */ +#define BESR_DSES 0x80000000 /* Data-Side Error Status */ +#define BESR_DMES 0x40000000 /* DMA Error Status */ +#define BESR_RWS 0x20000000 /* Read/Write Status */ +#define BESR_ETMASK 0x1C000000 /* Error Type */ +#define ET_PROT 0 +#define ET_PARITY 1 +#define ET_NCFG 2 +#define ET_BUSERR 4 +#define ET_BUSTO 6 + +#define CHR1_CETE 0x00800000 /* CPU external timer enable */ +#define CHR1_PCIPW 0x00008000 /* PCI Int enable/Peripheral Write enable */ + +#define DCRN_CICCR (DCRN_CIC_BASE + 0x0) /* CIC Control Register */ +#define DCRN_DMAS1 (DCRN_CIC_BASE + 0x1) /* DMA Select1 Register */ +#define DCRN_DMAS2 (DCRN_CIC_BASE + 0x2) /* DMA Select2 Register */ +#define DCRN_CICVCR (DCRN_CIC_BASE + 0x3) /* CIC Video COntro Register */ +#define DCRN_CICSEL3 (DCRN_CIC_BASE + 0x5) /* CIC Select 3 Register */ +#define DCRN_SGPO (DCRN_CIC_BASE + 0x6) /* CIC GPIO Output Register */ +#define DCRN_SGPOD (DCRN_CIC_BASE + 0x7) /* CIC GPIO OD Register */ +#define DCRN_SGPTC (DCRN_CIC_BASE + 0x8) /* CIC GPIO Tristate Ctrl Reg */ +#define DCRN_SGPI (DCRN_CIC_BASE + 0x9) /* CIC GPIO Input Reg */ + +#define DCRN_DCRXICR (DCRN_DCRX_BASE + 0x0) /* Internal Control Register */ +#define DCRN_DCRXISR (DCRN_DCRX_BASE + 0x1) /* Internal Status Register */ +#define DCRN_DCRXECR (DCRN_DCRX_BASE + 0x2) /* External Control Register */ +#define DCRN_DCRXESR (DCRN_DCRX_BASE + 0x3) /* External Status Register */ +#define DCRN_DCRXTAR (DCRN_DCRX_BASE + 0x4) /* Target Address Register */ +#define DCRN_DCRXTDR (DCRN_DCRX_BASE + 0x5) /* Target Data Register */ +#define DCRN_DCRXIGR (DCRN_DCRX_BASE + 0x6) /* Interrupt Generation Register */ +#define DCRN_DCRXBCR (DCRN_DCRX_BASE + 0x7) /* Line Buffer Control Register */ + +#define DCRN_BRCRH0 (DCRN_EBIMC_BASE + 0x0) /* Bus Region Config High 0 */ +#define DCRN_BRCRH1 (DCRN_EBIMC_BASE + 0x1) /* Bus Region Config High 1 */ +#define DCRN_BRCRH2 (DCRN_EBIMC_BASE + 0x2) /* Bus Region Config High 2 */ +#define DCRN_BRCRH3 (DCRN_EBIMC_BASE + 0x3) /* Bus Region Config High 3 */ +#define DCRN_BRCRH4 (DCRN_EBIMC_BASE + 0x4) /* Bus Region Config High 4 */ +#define DCRN_BRCRH5 (DCRN_EBIMC_BASE + 0x5) /* Bus Region Config High 5 */ +#define DCRN_BRCRH6 (DCRN_EBIMC_BASE + 0x6) /* Bus Region Config High 6 */ +#define DCRN_BRCRH7 (DCRN_EBIMC_BASE + 0x7) /* Bus Region Config High 7 */ +#define DCRN_BRCR0 (DCRN_EBIMC_BASE + 0x10) /* BRC 0 */ +#define DCRN_BRCR1 (DCRN_EBIMC_BASE + 0x11) /* BRC 1 */ +#define DCRN_BRCR2 (DCRN_EBIMC_BASE + 0x12) /* BRC 2 */ +#define DCRN_BRCR3 (DCRN_EBIMC_BASE + 0x13) /* BRC 3 */ +#define DCRN_BRCR4 (DCRN_EBIMC_BASE + 0x14) /* BRC 4 */ +#define DCRN_BRCR5 (DCRN_EBIMC_BASE + 0x15) /* BRC 5 */ +#define DCRN_BRCR6 (DCRN_EBIMC_BASE + 0x16) /* BRC 6 */ +#define DCRN_BRCR7 (DCRN_EBIMC_BASE + 0x17) /* BRC 7 */ +#define DCRN_BEAR0 (DCRN_EBIMC_BASE + 0x20) /* Bus Error Address Register */ +#define DCRN_BESR0 (DCRN_EBIMC_BASE + 0x21) /* Bus Error Status Register */ +#define DCRN_BIUCR (DCRN_EBIMC_BASE + 0x2A) /* Bus Interfac Unit Ctrl Reg */ + +#define DCRN_RTC_FPC0_CNTL (DCRN_RTCFP_BASE + 0x00) /* RTC cntl */ +#define DCRN_RTC_FPC0_INT (DCRN_RTCFP_BASE + 0x01) /* RTC Interrupt */ +#define DCRN_RTC_FPC0_TIME (DCRN_RTCFP_BASE + 0x02) /* RTC time reg */ +#define DCRN_RTC_FPC0_ALRM (DCRN_RTCFP_BASE + 0x03) /* RTC Alarm reg */ +#define DCRN_RTC_FPC0_D1 (DCRN_RTCFP_BASE + 0x04) /* LED Data 1 */ +#define DCRN_RTC_FPC0_D2 (DCRN_RTCFP_BASE + 0x05) /* LED Data 2 */ +#define DCRN_RTC_FPC0_D3 (DCRN_RTCFP_BASE + 0x06) /* LED Data 3 */ +#define DCRN_RTC_FPC0_D4 (DCRN_RTCFP_BASE + 0x07) /* LED Data 4 */ +#define DCRN_RTC_FPC0_D5 (DCRN_RTCFP_BASE + 0x08) /* LED Data 5 */ +#define DCRN_RTC_FPC0_FCNTL (DCRN_RTCFP_BASE + 0x09) /* LED control */ +#define DCRN_RTC_FPC0_BRT (DCRN_RTCFP_BASE + 0x0A) /* Brightness cntl */ + +#include + +#endif /* __ASM_IBMSTBX25_H__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/ocotea.c linux-2.4.26/arch/ppc/platforms/ocotea.c --- linux-2.4.25/arch/ppc/platforms/ocotea.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ocotea.c 2004-04-14 06:05:27.000000000 -0700 @@ -44,6 +44,8 @@ #include #include +#include + extern void abort(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); @@ -79,11 +81,13 @@ static int ocotea_show_cpuinfo(struct seq_file *m) { + ibm440gx_show_cpuinfo(m); seq_printf(m, "vendor\t\t: IBM\n"); seq_printf(m, "machine\t\t: PPC440GX EVB (Ocotea)\n"); return 0; } + static inline int ocotea_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) { @@ -147,7 +151,7 @@ /* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */ PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH); PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL); - PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA); + PCIX_WRITEL(0x80000007, PCIX0_PIM0SA); eieio(); } @@ -205,14 +209,14 @@ TODC_ALLOC(); static void __init -ocotea_early_serial_map(void) +ocotea_early_serial_map(const struct ibm44x_clocks* clks) { struct serial_struct serial_req; /* Setup ioremapped serial port access */ memset(&serial_req, 0, sizeof(serial_req)); serial_req.line = 0; - serial_req.baud_base = BASE_BAUD; + serial_req.baud_base = clks->uart0 / 16; serial_req.port = 0; serial_req.irq = 0; serial_req.flags = ASYNC_BOOT_AUTOCONF; @@ -231,6 +235,7 @@ /* Assume early_serial_setup() doesn't modify serial_req */ serial_req.line = 1; + serial_req.baud_base = clks->uart1 / 16; serial_req.port = 1; serial_req.irq = 1; serial_req.iomem_base = ioremap64(PPC440GX_UART1_ADDR, 8); @@ -251,6 +256,7 @@ unsigned char *addr; unsigned long long mac64; bd_t *bip = (bd_t *) __res; + struct ibm44x_clocks clocks; /* Retrieve MAC addresses from flash */ addr = ioremap64(OCOTEA_MAC_BASE, OCOTEA_MAC_SIZE); @@ -271,7 +277,18 @@ */ mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM)); #endif - + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + bip->bi_opb_busfreq = clocks.opb; + + /* Use IIC in standard (100 kHz) mode */ + bip->bi_iic_fast[0] = bip->bi_iic_fast[1] = 0; + /* Setup TODC access */ TODC_INIT(TODC_TYPE_DS1743, 0, @@ -300,7 +317,7 @@ conswitchp = &dummy_con; #endif - ocotea_early_serial_map(); + ocotea_early_serial_map(&clocks); /* Identify the system */ printk("IBM Ocotea port (MontaVista Software, Inc. )\n"); @@ -405,6 +422,9 @@ { parse_bootinfo(find_bootinfo()); + /* Disable L2-Cache due to hardware issues */ + ibm440gx_l2c_disable(); + ppc_md.setup_arch = ocotea_setup_arch; ppc_md.show_cpuinfo = ocotea_show_cpuinfo; ppc_md.init_IRQ = ocotea_init_irq; diff -urN linux-2.4.25/arch/ppc/platforms/ocotea.h linux-2.4.26/arch/ppc/platforms/ocotea.h --- linux-2.4.25/arch/ppc/platforms/ocotea.h 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/ocotea.h 2004-04-14 06:05:27.000000000 -0700 @@ -25,7 +25,7 @@ #define PPC44x_EMAC0_MR0 0xE0000800 /* Location of MAC addresses in firmware */ -#define OCOTEA_MAC_BASE (OCOTEA_SMALL_FLASH_HIGH+0xc0500) +#define OCOTEA_MAC_BASE (OCOTEA_SMALL_FLASH_HIGH+0xb0500) #define OCOTEA_MAC_SIZE 0x200 #define OCOTEA_MAC1_OFFSET 0x100 @@ -55,6 +55,9 @@ #define UART0_IO_BASE (u8 *) 0xE0000200 #define UART1_IO_BASE (u8 *) 0xE0000300 +/* This value is used only to fill something in STD_UART_OP definition, + actual value is determined in ocotea_early_serial_map. --ebs +*/ #define BASE_BAUD 11059200/16 #define STD_UART_OP(num) \ { 0, BASE_BAUD, 0, UART##num##_INT, \ diff -urN linux-2.4.25/arch/ppc/platforms/pq2ads.h linux-2.4.26/arch/ppc/platforms/pq2ads.h --- linux-2.4.25/arch/ppc/platforms/pq2ads.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/pq2ads.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,89 @@ + +/* + * A collection of structures, addresses, and values associated with + * the Motorola MPC8260ADS/MPC8266ADS-PCI boards. + * Copied from the RPX-Classic and SBS8260 stuff. + * + * Copyright (c) 2001 Dan Malek (dan@mvista.com) + */ +#ifdef __KERNEL__ +#ifndef __MACH_ADS8260_DEFS +#define __MACH_ADS8260_DEFS + +#include + +#include + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define CPM_MAP_ADDR ((uint)0xf0000000) +#define BCSR_ADDR ((uint)0xf4500000) +#define BCSR_SIZE ((uint)(32 * 1024)) + +/* The ADS8260 has 16, 32-bit wide control/status registers, accessed + * only on word boundaries. + * Not all are used (yet), or are interesting to us (yet). + */ + +/* Things of interest in the CSR. +*/ +#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */ +#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */ +#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable */ +#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */ +#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 == enable */ +#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 == enable */ + +#define PHY_INTERRUPT SIU_INT_IRQ7 + +#ifdef CONFIG_PCI +/* PCI interrupt controller */ +#define PCI_INT_STAT_REG 0xF8200000 +#define PCI_INT_MASK_REG 0xF8200004 +#define PIRQA (NR_SIU_INTS + 0) +#define PIRQB (NR_SIU_INTS + 1) +#define PIRQC (NR_SIU_INTS + 2) +#define PIRQD (NR_SIU_INTS + 3) + +/* + * PCI memory map definitions for MPC8266ADS-PCI. + * + * processor view + * local address PCI address target + * 0x80000000-0x9FFFFFFF 0x80000000-0x9FFFFFFF PCI mem with prefetch + * 0xA0000000-0xBFFFFFFF 0xA0000000-0xBFFFFFFF PCI mem w/o prefetch + * 0xF4000000-0xF7FFFFFF 0x00000000-0x03FFFFFF PCI IO + * + * PCI master view + * local address PCI address target + * 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory + */ + +/* window for a PCI master to access MPC8266 memory */ +#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */ +#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */ + +/* window for the processor to access PCI memory with prefetching */ +#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */ +#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */ +#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */ + +/* window for the processor to access PCI memory without prefetching */ +#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */ +#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */ +#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */ + +/* window for the processor to access PCI I/O */ +#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */ +#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */ +#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */ + +#define _IO_BASE PCI_MSTR_IO_LOCAL +#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL +#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS +#endif /* CONFIG_PCI */ + +#endif /* __MACH_ADS8260_DEFS */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/redwood5.c linux-2.4.26/arch/ppc/platforms/redwood5.c --- linux-2.4.25/arch/ppc/platforms/redwood5.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/redwood5.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,82 @@ +/* + * + * Copyright 2000-2001 MontaVista Software Inc. + * Completed implementation. + * Author: Armin Kuster + * + * Module name: redwood5.c + * + * Description: + * IBM redwood5 eval board file + * + * History: 12/29/2001 - Armin + * initail release + * + * Please read the COPYING file for all license details. + */ + +#include +#include +#include +#include +#include + +void __init +board_setup_arch(void) +{ + + bd_t *bip = (bd_t *)__res; + +#ifdef CONFIG_DEBUG_BRINGUP + printk("\n"); + printk("machine\t: %s\n", PPC4xx_MACHINE_NAME); + printk("\n"); + printk("bi_s_version\t %s\n", bip->bi_s_version); + printk("bi_r_version\t %s\n", bip->bi_r_version); + printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize,bip->bi_memsize/(1024*1000)); + printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0, + bip->bi_enetaddr[0], bip->bi_enetaddr[1], + bip->bi_enetaddr[2], bip->bi_enetaddr[3], + bip->bi_enetaddr[4], bip->bi_enetaddr[5]); + + printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n", + bip->bi_intfreq, bip->bi_intfreq/ 1000000); + + printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n", + bip->bi_busfreq, bip->bi_busfreq / 1000000 ); + printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n", + bip->bi_tbfreq, bip->bi_tbfreq/1000000); + + printk("\n"); +#endif + +} + +void __init +board_io_mapping(void) +{ + int i; + + for (i = 0; i < 16; i++) { + unsigned long v, p; + + /* 0x400x0000 -> 0xe00x0000 */ + p = 0x40000000 | (i << 16); + v = STB04xxx_IO_BASE | (i << 16); + + io_block_mapping(v, p, PAGE_SIZE, + _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | _PAGE_GUARDED); + } + + +} + +void __init +board_setup_irq(void) +{ +} + +void __init +board_init(void) +{ +} diff -urN linux-2.4.25/arch/ppc/platforms/redwood5.h linux-2.4.26/arch/ppc/platforms/redwood5.h --- linux-2.4.25/arch/ppc/platforms/redwood5.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/redwood5.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * PPC405 modifications + * Author: MontaVista Software, Inc. + * Armin Kuster + * + * Module name: redwood5.h + * + * Description: + * Macros, definitions, and data structures specific to the IBM PowerPC + * STB03xxx "Redwood" evaluation board. + * + * Please read the COPYING file for all license details. + */ + +#ifdef __KERNEL__ +#ifndef __ASM_REDWOOD5_H__ +#define __ASM_REDWOOD5_H__ + +/* Redwood5 has an STB04xxx core */ +#include + +#ifndef __ASSEMBLY__ +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned int bi_dummy; /* field shouldn't exist */ + unsigned char bi_enetaddr[6]; /* Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* Bus speed, in Hz */ + unsigned int bi_tbfreq; /* Software timebase freq */ + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + int bi_iic_fast[2]; /* Use fast i2c mode */ +} bd_t; +#endif /* !__ASSEMBLY__ */ + + +#define SMC91111_BASE_ADDR 0xf2000300 +#define SMC91111_IRQ 28 + +#ifdef MAX_HWIFS +#undef MAX_HWIFS +#endif +#define MAX_HWIFS 1 + +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 + +#define BASE_BAUD (378000000 / 18 / 16) + +#define PPC4xx_MACHINE_NAME "IBM Redwood5" + +#endif /* __ASM_REDWOOD5_H__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/redwood6.c linux-2.4.26/arch/ppc/platforms/redwood6.c --- linux-2.4.25/arch/ppc/platforms/redwood6.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/redwood6.c 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,174 @@ +/* + * + * Module name: redwood6.c + * + * Description: + * IBM redwood6 eval board file + * + * Author: Armin Kuster + * Copyright 2002 MontaVista Software 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * History: July 10, 2002 - Armin + * initial release + * + * : July 16, 2002 - Armin + * added xilinx init code for ide interface + * added IRQ table + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * Define all of the IRQ senses and polarities. + */ + +static u_char redwood6_IRQ_initsenses[] __initdata = { + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 0: RTC/FPC */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 1: Transport */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 2: Audio Dec */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 3: Video Dec */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 4: DMA Chan 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 5: DMA Chan 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 6: DMA Chan 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 7: DMA Chan 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 8: SmartCard 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 9: IIC0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 10: IRR */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 11: Cap Timers */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 12: Cmp Timers */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 13: Serial Port */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 14: Soft Modem */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 15: Down Ctrs */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 16: SmartCard 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 17: Ext Int 7 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 18: Ext Int 8 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 19: Ext Int 9 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 20: Serial 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 21: Serial 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 22: Serial 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 23: XPT_DMA */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* 24: DCR timeout */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 25: Ext Int 0 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 26: Ext Int 1 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 27: Ext Int 2 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 28: Ext Int 3 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 29: Ext Int 4 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 30: Ext Int 5 */ + (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* 31: Ext Int 6 */ +}; + + +void __init +board_setup_arch(void) +{ +#ifdef CONFIG_IDE + void *xilinx, *xilinx_1, *xilinx_2; + unsigned short us_reg5; + + xilinx = (unsigned long) ioremap(IDE_XLINUX_MUX_BASE, 0x10); + /* init xilinx control registers - enable ide mux, clear reset bit */ + if (!xilinx) { + printk(KERN_CRIT + "redwood6_setup_arch() xilinxi ioremap failed\n"); + return; + } + xilinx_1 = xilinx + 0xa; + xilinx_2 = xilinx + 0xe; + + us_reg5 = readb(xilinx_1); + writeb(0x01d1, xilinx_1); + writeb(0x0008, xilinx_2); + + udelay(10 * 1000); + + writeb(0x01d1, xilinx_1); + writeb(0x0008, xilinx_2); +#endif + +#ifdef DEBUG_BRINGUP + bd_t *bip = (bd_t *) __res; + printk("\n"); + printk("machine\t: %s\n", PPC4xx_MACHINE_NAME); + printk("\n"); + printk("bi_s_version\t %s\n", bip->bi_s_version); + printk("bi_r_version\t %s\n", bip->bi_r_version); + printk("bi_memsize\t 0x%8.8x\t %dMBytes\n", bip->bi_memsize, + bip->bi_memsize / (1024 * 1000)); + printk("bi_enetaddr %d\t %2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x\n", 0, + bip->bi_enetaddr[0], bip->bi_enetaddr[1], bip->bi_enetaddr[2], + bip->bi_enetaddr[3], bip->bi_enetaddr[4], bip->bi_enetaddr[5]); + + printk("bi_intfreq\t 0x%8.8x\t clock:\t %dMhz\n", + bip->bi_intfreq, bip->bi_intfreq / 1000000); + + printk("bi_busfreq\t 0x%8.8x\t plb bus clock:\t %dMHz\n", + bip->bi_busfreq, bip->bi_busfreq / 1000000); + printk("bi_tbfreq\t 0x%8.8x\t TB freq:\t %dMHz\n", + bip->bi_tbfreq, bip->bi_tbfreq / 1000000); + + printk("\n"); +#endif + ibm4xxPIC_InitSenses = redwood6_IRQ_initsenses; + ibm4xxPIC_NumInitSenses = sizeof(redwood6_IRQ_initsenses); + + /* Identify the system */ + printk(KERN_INFO "IBM Redwood6 (STBx25XX) Platform\n"); + printk(KERN_INFO + "Port by MontaVista Software, Inc. (source@mvista.com)\n"); +} + +void __init +board_io_mapping(void) +{ + int i; + + for (i = 0; i < 16; i++) { + unsigned long v, p; + + /* 0x400x0000 -> 0xe00x0000 */ + p = 0x40000000 | (i << 16); + v = STBx25xx_IO_BASE | (i << 16); + + io_block_mapping(v, p, PAGE_SIZE, + _PAGE_NO_CACHE | pgprot_val(PAGE_KERNEL) | + _PAGE_GUARDED); + } +} + +void __init +board_setup_irq(void) +{ +} + +void __init +board_init(void) +{ +} diff -urN linux-2.4.25/arch/ppc/platforms/redwood6.h linux-2.4.26/arch/ppc/platforms/redwood6.h --- linux-2.4.25/arch/ppc/platforms/redwood6.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/redwood6.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,78 @@ +/* + * Author: MontaVista Software, Inc. + * Armin Kuster + * + * Module name: redwood6.h + * + * Description: + * Macros, definitions, and data structures specific to the IBM PowerPC + * STBx25xx "Redwood6" evaluation board. + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * Armin Kuster + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_REDWOOD5_H__ +#define __ASM_REDWOOD5_H__ + +/* Redwood6 has an STBx25xx core */ +#include + +#ifndef __ASSEMBLY__ +typedef struct board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ + unsigned int bi_dummy; /* field shouldn't exist */ + unsigned char bi_enetaddr[6]; /* Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* Bus speed, in Hz */ + unsigned int bi_tbfreq; /* Software timebase freq */ + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + int bi_iic_fast[1]; /* Use fast i2c mode */ +} bd_t; +#endif /* !__ASSEMBLY__ */ + +#define SMC91111_BASE_ADDR 0xf2030300 +#define SMC91111_IRQ 27 +#define IDE_XLINUX_MUX_BASE 0xf2040000 +#define IDE_DMA_ADDR 0xfce00000 + +#ifdef MAX_HWIFS +#undef MAX_HWIFS +#endif +#define MAX_HWIFS 1 + +#define _IO_BASE 0 +#define _ISA_MEM_BASE 0 +#define PCI_DRAM_OFFSET 0 + +#define BASE_BAUD (378000000 / 18 / 16) + +#define PPC4xx_MACHINE_NAME "IBM Redwood6" + +#endif /* __ASM_REDWOOD5_H__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc/platforms/rpx8260.h linux-2.4.26/arch/ppc/platforms/rpx8260.h --- linux-2.4.25/arch/ppc/platforms/rpx8260.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/ppc/platforms/rpx8260.h 2004-04-14 06:05:27.000000000 -0700 @@ -0,0 +1,73 @@ + +/* + * A collection of structures, addresses, and values associated with + * the Embedded Planet RPX6 (or RPX Super) MPC8260 board. + * Copied from the RPX-Classic and SBS8260 stuff. + * + * Copyright (c) 2001 Dan Malek (dan@embeddededge.com) + */ +#ifdef __KERNEL__ +#ifndef __MACH_RPXSUPER_DEFS +#define __MACH_RPXSUPER_DEFS + +/* A Board Information structure that is given to a program when + * prom starts it up. + */ +typedef struct bd_info { + unsigned int bi_memstart; /* Memory start address */ + unsigned int bi_memsize; /* Memory (end) size in bytes */ + unsigned int bi_nvsize; /* NVRAM size in bytes (can be 0) */ + unsigned int bi_intfreq; /* Internal Freq, in Hz */ + unsigned int bi_busfreq; /* Bus Freq, in MHz */ + unsigned int bi_cpmfreq; /* CPM Freq, in MHz */ + unsigned int bi_brgfreq; /* BRG Freq, in MHz */ + unsigned int bi_vco; /* VCO Out from PLL */ + unsigned int bi_baudrate; /* Default console baud rate */ + unsigned int bi_immr; /* IMMR when called from boot rom */ + unsigned char bi_enetaddr[6]; +} bd_t; + +extern bd_t m8xx_board_info; + +/* Memory map is configured by the PROM startup. + * We just map a few things we need. The CSR is actually 4 byte-wide + * registers that can be accessed as 8-, 16-, or 32-bit values. + */ +#define CPM_MAP_ADDR ((uint)0xf0000000) +#define RPX_CSR_ADDR ((uint)0xfa000000) +#define RPX_CSR_SIZE ((uint)(512 * 1024)) +#define RPX_NVRTC_ADDR ((uint)0xfa080000) +#define RPX_NVRTC_SIZE ((uint)(512 * 1024)) + +/* The RPX6 has 16, byte wide control/status registers. + * Not all are used (yet). + */ +extern volatile u_char *rpx6_csr_addr; + +/* Things of interest in the CSR. +*/ +#define BCSR0_ID_MASK ((u_char)0xf0) /* Read only */ +#define BCSR0_SWITCH_MASK ((u_char)0x0f) /* Read only */ +#define BCSR1_XCVR_SMC1 ((u_char)0x80) +#define BCSR1_XCVR_SMC2 ((u_char)0x40) +#define BCSR2_FLASH_WENABLE ((u_char)0x20) +#define BCSR2_NVRAM_ENABLE ((u_char)0x10) +#define BCSR2_ALT_IRQ2 ((u_char)0x08) +#define BCSR2_ALT_IRQ3 ((u_char)0x04) +#define BCSR2_PRST ((u_char)0x02) /* Force reset */ +#define BCSR2_ENPRST ((u_char)0x01) /* Enable POR */ +#define BCSR3_MODCLK_MASK ((u_char)0xe0) +#define BCSR3_ENCLKHDR ((u_char)0x10) +#define BCSR3_LED5 ((u_char)0x04) /* 0 == on */ +#define BCSR3_LED6 ((u_char)0x02) /* 0 == on */ +#define BCSR3_LED7 ((u_char)0x01) /* 0 == on */ +#define BCSR4_EN_PHY ((u_char)0x80) /* Enable PHY */ +#define BCSR4_EN_MII ((u_char)0x40) /* Enable PHY */ +#define BCSR4_MII_READ ((u_char)0x04) +#define BCSR4_MII_MDC ((u_char)0x02) +#define BCSR4_MII_MDIO ((u_char)0x02) +#define BCSR13_FETH_IRQMASK ((u_char)0xf0) +#define BCSR15_FETH_IRQ ((u_char)0x20) + +#endif +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/arch/ppc64/kernel/lparcfg.c linux-2.4.26/arch/ppc64/kernel/lparcfg.c --- linux-2.4.25/arch/ppc64/kernel/lparcfg.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.26/arch/ppc64/kernel/lparcfg.c 2004-04-14 06:05:27.000000000 -0700 @@ -326,7 +326,7 @@ system_potential_processors = get_splpar_potential_characteristics(); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_active_processors=%d\n", - (h_resource >> 2*8) && 0xffff); + (h_resource >> 2*8) & 0xffff); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, "system_potential_processors=%d\n", system_potential_processors); @@ -366,16 +366,16 @@ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "pool=%d\n", (h_aggregation >> 0*8)&&0xffff); + "pool=%d\n", (h_aggregation >> 0*8)&0xffff); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "pool_capacity=%d\n", (h_resource >> 3*8) &&0xffff); + "pool_capacity=%d\n", (h_resource >> 3*8) &0xffff); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "group=%d\n", (h_aggregation >> 2*8)&&0xffff); + "group=%d\n", (h_aggregation >> 2*8)&0xffff); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, - "capped=%d\n", (h_resource >> 6*8)&&0x40); + "capped=%d\n", (h_resource >> 6*8)&0x40); n += snprintf(buf+n, LPARCFG_BUFF_SIZE - n, "capacity_weight=%d\n", (int)(h_resource>>5*8)&0xFF); diff -urN linux-2.4.25/arch/sparc/defconfig linux-2.4.26/arch/sparc/defconfig --- linux-2.4.25/arch/sparc/defconfig 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/sparc/defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -161,9 +161,11 @@ # CONFIG_IPV6_SCTP__=m CONFIG_IP_SCTP=m -# CONFIG_SCTP_ADLER32 is not set # CONFIG_SCTP_DBG_MSG is not set # CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -362,6 +364,7 @@ CONFIG_LOCKD=y CONFIG_SMB_FS=m # CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_SMB_UNIX is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_NCPFS_IOCTL_LOCKING is not set diff -urN linux-2.4.25/arch/sparc/kernel/sys_sunos.c linux-2.4.26/arch/sparc/kernel/sys_sunos.c --- linux-2.4.25/arch/sparc/kernel/sys_sunos.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/sparc/kernel/sys_sunos.c 2004-04-14 06:05:27.000000000 -0700 @@ -688,8 +688,8 @@ static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int server_fd; - char *the_name; + int server_fd, err; + char *the_name, *mount_page; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args sunos_mount; @@ -742,7 +742,16 @@ linux_nfs_mount.hostname [255] = 0; putname (the_name); - return do_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount); + mount_page = (char *) get_zeroed_page(GFP_KERNEL); + if (!mount_page) + return -ENOMEM; + + memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount)); + + err = do_mount("", dir_name, "nfs", linux_flags, mount_page); + + free_page((unsigned long) mount_page); + return err; } asmlinkage int diff -urN linux-2.4.25/arch/sparc64/defconfig linux-2.4.26/arch/sparc64/defconfig --- linux-2.4.25/arch/sparc64/defconfig 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/sparc64/defconfig 2004-04-14 06:05:27.000000000 -0700 @@ -70,6 +70,7 @@ # CONFIG_PARPORT_SERIAL is not set CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_PC_PCMCIA is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set @@ -122,6 +123,7 @@ CONFIG_FB_PCI=y CONFIG_FB_ATY=y CONFIG_FB_ATY_CT=y +# CONFIG_FB_IT8181 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -312,11 +314,12 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=m CONFIG_IP_SCTP=m -# CONFIG_SCTP_ADLER32 is not set # CONFIG_SCTP_DBG_MSG is not set # CONFIG_SCTP_DBG_OBJCNT is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set # CONFIG_ATM is not set CONFIG_VLAN_8021Q=m @@ -351,12 +354,14 @@ CONFIG_NET_SCH_CBQ=m CONFIG_NET_SCH_HTB=m CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_HFSC=m CONFIG_NET_SCH_PRIO=m CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m CONFIG_NET_SCH_TEQL=m CONFIG_NET_SCH_TBF=m CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DELAY=m CONFIG_NET_SCH_DSMARK=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_QOS=y @@ -453,6 +458,7 @@ CONFIG_BLK_DEV_ATARAID=m CONFIG_BLK_DEV_ATARAID_PDC=m CONFIG_BLK_DEV_ATARAID_HPT=m +CONFIG_BLK_DEV_ATARAID_MEDLEY=m # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -617,6 +623,7 @@ CONFIG_FEALNX=m CONFIG_NATSEMI=m CONFIG_NE2K_PCI=m +CONFIG_FORCEDETH=m # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -738,8 +745,8 @@ CONFIG_BEFS_FS=m # CONFIG_BEFS_DEBUG is not set CONFIG_BFS_FS=m -CONFIG_EXT3_FS=m -CONFIG_JBD=m +CONFIG_EXT3_FS=y +CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m @@ -749,7 +756,7 @@ # CONFIG_JFFS_FS is not set # CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set +CONFIG_TMPFS=y CONFIG_RAMFS=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y @@ -763,8 +770,8 @@ # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set @@ -974,7 +981,6 @@ CONFIG_USB_RTL8150=m CONFIG_USB_KAWETH=m CONFIG_USB_CATC=m -CONFIG_USB_AX8817X=m CONFIG_USB_CDCETHER=m CONFIG_USB_USBNET=m @@ -1034,13 +1040,20 @@ # Support for USB gadgets # CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_NET2280=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_CONTROLLER is not set +CONFIG_USB_NET2280=y +CONFIG_USB_GADGET_CONTROLLER=y +CONFIG_USB_GADGET_DUALSPEED=y # -# USB Peripheral Controller Drivers +# USB Gadget Drivers # -# CONFIG_USB_GADGET_CONTROLLER is not set -# CONFIG_USB_NET2280 is not set -# CONFIG_USB_GADGET_CONTROLLER is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_FILE_STORAGE_TEST is not set # # Bluetooth support @@ -1084,6 +1097,7 @@ # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_BUGVERBOSE is not set # CONFIG_DEBUG_DCFLUSH is not set +# CONFIG_DEBUG_BOOTMEM is not set # CONFIG_STACK_DEBUG is not set CONFIG_LOG_BUF_SHIFT=0 @@ -1104,6 +1118,8 @@ CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y # CONFIG_CRYPTO_TEST is not set diff -urN linux-2.4.25/arch/sparc64/kernel/sys_sparc32.c linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.25/arch/sparc64/kernel/sys_sparc32.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c 2004-04-14 06:05:27.000000000 -0700 @@ -1799,14 +1799,13 @@ if (err) goto out; - if (!type_page) { - err = -EINVAL; - goto out; + if (type_page) { + is_smb = !strcmp((char *)type_page, SMBFS_NAME); + is_ncp = !strcmp((char *)type_page, NCPFS_NAME); + } else { + is_smb = is_ncp = 0; } - is_smb = !strcmp((char *)type_page, SMBFS_NAME); - is_ncp = !strcmp((char *)type_page, NCPFS_NAME); - err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); if (err) goto type_out; diff -urN linux-2.4.25/arch/sparc64/kernel/sys_sunos32.c linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c --- linux-2.4.25/arch/sparc64/kernel/sys_sunos32.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c 2004-04-14 06:05:28.000000000 -0700 @@ -654,8 +654,8 @@ /* XXXXXXXXXXXXXXXXXXXX */ static int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) { - int server_fd; - char *the_name; + int server_fd, err; + char *the_name, *mount_page; struct nfs_mount_data linux_nfs_mount; struct sunos_nfs_mount_args sunos_mount; @@ -708,7 +708,16 @@ linux_nfs_mount.hostname [255] = 0; putname (the_name); - return do_mount ("", dir_name, "nfs", linux_flags, &linux_nfs_mount); + mount_page = (char *) get_zeroed_page(GFP_KERNEL); + if (!mount_page) + return -ENOMEM; + + memcpy(mount_page, &linux_nfs_mount, sizeof(linux_nfs_mount)); + + err = do_mount("", dir_name, "nfs", linux_flags, mount_page); + + free_page((unsigned long) mount_page); + return err; } /* XXXXXXXXXXXXXXXXXXXX */ diff -urN linux-2.4.25/arch/sparc64/mm/modutil.c linux-2.4.26/arch/sparc64/mm/modutil.c --- linux-2.4.25/arch/sparc64/mm/modutil.c 2001-12-21 09:41:53.000000000 -0800 +++ linux-2.4.26/arch/sparc64/mm/modutil.c 2004-04-14 06:05:28.000000000 -0700 @@ -11,9 +11,9 @@ #include #include -static struct vm_struct * modvmlist = NULL; +static struct vm_struct *modvmlist = NULL; -void module_unmap (void * addr) +void __module_unmap(void *addr, int free_area_pages) { struct vm_struct **p, *tmp; @@ -26,7 +26,9 @@ for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; - vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); + if (free_area_pages) + vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), + tmp->size); kfree(tmp); return; } @@ -34,13 +36,19 @@ printk("Trying to unmap nonexistent module vm area (%p)\n", addr); } -void * module_map (unsigned long size) +void module_unmap(void *addr) +{ + __module_unmap(addr, 1); +} + +void *module_map (unsigned long size) { void * addr; struct vm_struct **p, *tmp, *area; size = PAGE_ALIGN(size); - if (!size || size > MODULES_LEN) return NULL; + if (!size || size > MODULES_LEN) + return NULL; addr = (void *) MODULES_VADDR; for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) { @@ -48,17 +56,19 @@ break; addr = (void *) (tmp->size + (unsigned long) tmp->addr); } - if ((unsigned long) addr + size >= MODULES_END) return NULL; + if ((unsigned long) addr + size >= MODULES_END) + return NULL; area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL); - if (!area) return NULL; + if (!area) + return NULL; area->size = size + PAGE_SIZE; area->addr = addr; area->next = *p; *p = area; if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) { - module_unmap(addr); + __module_unmap(addr, 0); return NULL; } return addr; diff -urN linux-2.4.25/arch/x86_64/Makefile linux-2.4.26/arch/x86_64/Makefile --- linux-2.4.25/arch/x86_64/Makefile 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/Makefile 2004-04-14 06:05:28.000000000 -0700 @@ -19,7 +19,7 @@ # 20010105 Andi Kleen, add IA32 compiler. # ....and later removed it again.... # -# $Id: Makefile,v 1.34 2003/09/25 02:50:05 ak Exp $ +# $Id: Makefile,v 1.36 2004/02/27 18:30:19 ak Exp $ # # early bootup linking needs 32bit. You can either use real 32bit tools @@ -53,8 +53,16 @@ ifneq ($(CONFIG_X86_REMOTE_DEBUG),y) CFLAGS += -fno-asynchronous-unwind-tables endif +# this is needed right now for the 32bit ioctl code CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) +ifdef CONFIG_MK8 +CFLAGS += $(call check_gcc,-march=k8,) +endif +ifdef CONFIG_MPSC +CFLAGS += $(call check_gcc,-march=nocona,) +endif + HEAD := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o SUBDIRS := arch/x86_64/tools $(SUBDIRS) arch/x86_64/kernel arch/x86_64/mm arch/x86_64/lib diff -urN linux-2.4.25/arch/x86_64/boot/setup.S linux-2.4.26/arch/x86_64/boot/setup.S --- linux-2.4.25/arch/x86_64/boot/setup.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/boot/setup.S 2004-04-14 06:05:28.000000000 -0700 @@ -289,8 +289,9 @@ /* minimum CPUID flags for x86-64 */ /* see http://www.x86-64.org/lists/discuss/msg02971.html */ #define SSE_MASK ((1<<25)|(1<<26)) -#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \ - (1<<13)|(1<<15)|(1<<24)|(1<<29)) +#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\ + (1<<13)|(1<<15)|(1<<24)) +#define REQUIRED_MASK2 (1<<29) pushfl /* standard way to check for cpuid */ popl %eax @@ -302,10 +303,10 @@ popl %eax cmpl %eax,%ebx jz no_longmode /* cpu has no cpuid */ - movl $0x80000000,%eax + movl $0x0,%eax cpuid - cmpl $0x80000001,%eax - jb no_longmode /* no extended cpuid */ + cmpl $0x1,%eax + jb no_longmode /* no cpuid 1 */ xor %di,%di cmpl $0x68747541,%ebx /* AuthenticAMD */ jnz noamd @@ -315,11 +316,20 @@ jnz noamd mov $1,%di /* cpu is from AMD */ noamd: - movl $0x80000001,%eax + movl $0x1,%eax cpuid andl $REQUIRED_MASK1,%edx xorl $REQUIRED_MASK1,%edx jnz no_longmode + movl $0x80000000,%eax + cpuid + cmpl $0x80000001,%eax + jb no_longmode /* no extended cpuid */ + movl $0x80000001,%eax + cpuid + andl $REQUIRED_MASK2,%edx + xorl $REQUIRED_MASK2,%edx + jnz no_longmode sse_test: movl $1,%eax cpuid diff -urN linux-2.4.25/arch/x86_64/config.in linux-2.4.26/arch/x86_64/config.in --- linux-2.4.25/arch/x86_64/config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/config.in 2004-04-14 06:05:28.000000000 -0700 @@ -34,13 +34,19 @@ comment 'Processor type and features' choice 'Processor family' \ "AMD-Hammer CONFIG_MK8 \ + Intel-x86-64 CONFIG_MPSC \ Generic-x86-64 CONFIG_GENERIC_CPU" AMD-Hammer # # Define implied options from the CPU selection here # +if [ "$CONFIG_GENERIC_CPU" = "y" -o "$CONFIG_MPSC" = "y" ]; then +define_int CONFIG_X86_L1_CACHE_BYTES 128 +define_int CONFIG_X86_L1_CACHE_SHIFT 7 +else define_int CONFIG_X86_L1_CACHE_BYTES 64 define_int CONFIG_X86_L1_CACHE_SHIFT 6 +fi define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y @@ -58,6 +64,9 @@ bool 'Symmetric multi-processing support' CONFIG_SMP bool 'HPET timers' CONFIG_HPET_TIMER bool 'IOMMU support' CONFIG_GART_IOMMU +if [ "$CONFIG_GART_IOMMU" = "y" ]; then + bool 'SWIOTLB support' CONFIG_SWIOTLB +fi if [ "$CONFIG_GART_IOMMU" != "y" ]; then define_bool CONFIG_DUMMY_IOMMU y @@ -141,6 +150,7 @@ if [ "$CONFIG_IDE" != "n" ]; then source drivers/ide/Config.in else + define_bool CONFIG_BLK_DEV_IDE_MODES n define_bool CONFIG_BLK_DEV_HD n fi endmenu diff -urN linux-2.4.25/arch/x86_64/defconfig linux-2.4.26/arch/x86_64/defconfig --- linux-2.4.25/arch/x86_64/defconfig 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/defconfig 2004-04-14 06:05:28.000000000 -0700 @@ -26,10 +26,11 @@ # # Processor type and features # -CONFIG_MK8=y +# CONFIG_MK8 is not set +CONFIG_MPSC=y # CONFIG_GENERIC_CPU is not set -CONFIG_X86_L1_CACHE_BYTES=64 -CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_BYTES=128 +CONFIG_X86_L1_CACHE_SHIFT=7 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_MSR=y @@ -43,6 +44,7 @@ CONFIG_SMP=y CONFIG_HPET_TIMER=y CONFIG_GART_IOMMU=y +CONFIG_SWIOTLB=y CONFIG_HAVE_DEC_LOCK=y CONFIG_NR_CPUS=4 CONFIG_MCE=y @@ -159,6 +161,9 @@ # CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set +# CONFIG_SCTP_HMAC_NONE is not set +CONFIG_SCTP_HMAC_SHA1=y +# CONFIG_SCTP_HMAC_MD5 is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -254,7 +259,7 @@ # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_PIIX is not set +CONFIG_BLK_DEV_PIIX=y # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set @@ -275,6 +280,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -421,7 +427,8 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set -# CONFIG_E1000 is not set +CONFIG_E1000=y +# CONFIG_E1000_NAPI is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set diff -urN linux-2.4.25/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.26/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.4.25/arch/x86_64/ia32/ia32_ioctl.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/ia32/ia32_ioctl.c 2004-04-14 06:05:28.000000000 -0700 @@ -1,4 +1,4 @@ -/* $Id: ia32_ioctl.c,v 1.39 2004/01/29 03:01:57 ak Exp $ +/* $Id: ia32_ioctl.c,v 1.44 2004/03/21 22:32:20 ak Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) @@ -1785,7 +1785,10 @@ unsigned int buflen; int stat; __kernel_caddr_t32 sense; - __kernel_caddr_t32 reserved[3]; + unsigned char data_direction; + int quiet; + int timeout; + __kernel_caddr_t32 reserved[1]; }; static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -1827,17 +1830,25 @@ return -EFAULT; cdreadaudio.buf = (void *)A(addr); break; - case CDROM_SEND_PACKET: + case CDROM_SEND_PACKET: { + __kernel_caddr_t32 sense; karg = &cgc; err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); + err |= __get_user(sense, &((struct cdrom_generic_command32 *)arg)->sense); + err |= __get_user(cgc.data_direction, &((struct cdrom_generic_command32 *)arg)->data_direction); + err |= __get_user(cgc.timeout, &((struct cdrom_generic_command32 *)arg)->timeout); if (err) return -EFAULT; if (verify_area(VERIFY_WRITE, (void *)A(addr), cgc.buflen)) return -EFAULT; + if (sense && verify_area(VERIFY_WRITE, (void *)A(sense), sizeof(struct request_sense))) + return -EFAULT; cgc.buffer = (void *)A(addr); + cgc.sense = (void *)A(sense); break; + } default: do { static int count; @@ -2754,7 +2765,7 @@ struct file *file = fget(fd); struct tty_struct *real_tty; - if (!fd) + if (!file) return -EBADF; if (file->f_op->ioctl != tty_ioctl) return -EINVAL; @@ -3535,6 +3546,33 @@ return sys_ioctl(fd, cmd, (unsigned long) iwr); } +struct compat_ctrlmsg_ioctl { + struct usb_ctrlrequest req; + u32 data; +}; + +struct ctrlmsg_ioctl { + struct usb_ctrlrequest req; + void *data; +}; + +#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest) + +static int scanner_ioctl_ctrlmsg(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ctrlmsg_ioctl *c64; + struct compat_ctrlmsg_ioctl *c32 = (void *)arg; + u32 ptr; + + c64 = compat_alloc_user_space(sizeof(struct ctrlmsg_ioctl)); + + if (copy_in_user(&c64->req, &c32->req, sizeof(struct usb_ctrlrequest)) || + get_user(ptr, &c32->data) || + put_user((void *)(unsigned long)ptr, &c64->data)) + return -EFAULT; + return sys_ioctl(fd,cmd, (unsigned long)c64); +} + struct ioctl_trans { unsigned long cmd; int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); @@ -4423,6 +4461,17 @@ HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl) HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl) COMPATIBLE_IOCTL(SIOCGIWNAME) + +COMPATIBLE_IOCTL(SIOCSIFNAME) +/* usb scanner */ +#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int) +#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int) + +COMPATIBLE_IOCTL(SCANNER_IOCTL_VENDOR) +COMPATIBLE_IOCTL(SCANNER_IOCTL_PRODUCT) +/* USB scanner 'U' */ +HANDLE_IOCTL(SCANNER_IOCTL_CTRLMSG, scanner_ioctl_ctrlmsg) + IOCTL_TABLE_END #define IOCTL_HASHSIZE 256 @@ -4602,7 +4651,9 @@ t = (struct ioctl_trans *)t->next; if (t) { handler = t->handler; + lock_kernel(); error = handler(fd, cmd, arg, filp); + unlock_kernel(); } else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { error = siocdevprivate_ioctl(fd, cmd, arg); } else { diff -urN linux-2.4.25/arch/x86_64/ia32/ptrace32.c linux-2.4.26/arch/x86_64/ia32/ptrace32.c --- linux-2.4.25/arch/x86_64/ia32/ptrace32.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/ia32/ptrace32.c 2004-04-14 06:05:28.000000000 -0700 @@ -8,7 +8,7 @@ * This allows to access 64bit processes too; but there is no way to see the extended * register contents. * - * $Id: ptrace32.c,v 1.18 2004/01/29 00:50:29 ak Exp $ + * $Id: ptrace32.c,v 1.19 2004/01/29 03:31:13 ak Exp $ */ #include @@ -73,9 +73,12 @@ R32(eip, rip); R32(esp, rsp); - case offsetof(struct user32, regs.eflags): - stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; + case offsetof(struct user32, regs.eflags): { + __u64 *flags = &stack[offsetof(struct pt_regs, eflags)/8]; + val &= FLAG_MASK; + *flags = val | (*flags & ~FLAG_MASK); break; + } case offsetof(struct user32, u_debugreg[4]): case offsetof(struct user32, u_debugreg[5]): diff -urN linux-2.4.25/arch/x86_64/ia32/sys_ia32.c linux-2.4.26/arch/x86_64/ia32/sys_ia32.c --- linux-2.4.25/arch/x86_64/ia32/sys_ia32.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/ia32/sys_ia32.c 2004-04-14 06:05:28.000000000 -0700 @@ -16,7 +16,7 @@ * * This file assumes that there is a hole at the end of user address space. * - * $Id: sys_ia32.c,v 1.69 2004/01/29 02:52:13 ak Exp $ + * $Id: sys_ia32.c,v 1.70 2004/03/03 23:36:43 ak Exp $ */ #include @@ -1802,7 +1802,7 @@ return -EFAULT; } set_fs (KERNEL_DS); - ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); + ret = sys_rt_sigtimedwait(&s, &info, uts ? &t : NULL, sigsetsize); set_fs (old_fs); if (ret >= 0 && uinfo) { if (copy_to_user (uinfo, siginfo64to32(&info32, &info), @@ -3042,7 +3042,7 @@ static int __init ia32_init (void) { - printk("IA32 emulation $Id: sys_ia32.c,v 1.69 2004/01/29 02:52:13 ak Exp $\n"); + printk("IA32 emulation $Id: sys_ia32.c,v 1.70 2004/03/03 23:36:43 ak Exp $\n"); ia32_exec_domain.signal_map = default_exec_domain.signal_map; ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; register_exec_domain(&ia32_exec_domain); diff -urN linux-2.4.25/arch/x86_64/kernel/Makefile linux-2.4.26/arch/x86_64/kernel/Makefile --- linux-2.4.25/arch/x86_64/kernel/Makefile 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/Makefile 2004-04-14 06:05:28.000000000 -0700 @@ -14,8 +14,7 @@ O_TARGET := kernel.o - -export-objs := mtrr.o msr.o cpuid.o x8664_ksyms.o pci-gart.o setup.o +export-objs := mtrr.o msr.o cpuid.o x8664_ksyms.o pci-gart.o setup.o swiotlb.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ @@ -34,6 +33,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_SWIOTLB) += swiotlb.o obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o obj-$(CONFIG_MCE) += bluesmoke.o diff -urN linux-2.4.25/arch/x86_64/kernel/acpi.c linux-2.4.26/arch/x86_64/kernel/acpi.c --- linux-2.4.25/arch/x86_64/kernel/acpi.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/acpi.c 2004-04-14 06:05:28.000000000 -0700 @@ -47,14 +47,17 @@ #define PREFIX "ACPI: " -int acpi_lapic = 0; -int acpi_ioapic = 0; +int acpi_lapic; +int acpi_ioapic; +int acpi_strict; +acpi_interrupt_flags acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ -#ifdef CONFIG_ACPI_BOOT +int acpi_ht __initdata = 1; /* enable HT */ enum acpi_irq_model_id acpi_irq_model; @@ -226,6 +229,59 @@ return 0; } +/* + * Parse Interrupt Source Override for the ACPI SCI + */ +static void +acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) +{ + if (trigger == 0) /* compatible SCI trigger is level */ + trigger = 3; + + if (polarity == 0) /* compatible SCI polarity is low */ + polarity = 3; + + /* Command-line over-ride via acpi_sci= */ + if (acpi_sci_flags.trigger) + trigger = acpi_sci_flags.trigger; + + if (acpi_sci_flags.polarity) + polarity = acpi_sci_flags.polarity; + + /* + * mp_config_acpi_legacy_irqs() already setup IRQs < 16 + * If GSI is < 16, this will update its flags, + * else it will create a new mp_irqs[] entry. + */ + mp_override_legacy_irq(gsi, polarity, trigger, gsi); + + /* + * stash over-ride to indicate we've been here + * and for later update of acpi_fadt + */ + acpi_sci_override_gsi = gsi; + return; +} + +static int __init +acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt =0; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if (!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + +#ifdef CONFIG_ACPI_INTERPRETER + /* initialize sci_int early for INT_SRC_OVR MADT parsing */ + acpi_fadt.sci_int = fadt->sci_int; +#endif + + return 0; +} + static int __init acpi_parse_int_src_ovr ( @@ -239,6 +295,12 @@ acpi_table_print_madt_entry(header); + if (intsrc->bus_irq == acpi_fadt.sci_int) { + acpi_sci_ioapic_setup(intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); + return 0; + } + mp_override_legacy_irq ( intsrc->bus_irq, intsrc->flags.polarity, @@ -292,13 +354,12 @@ #ifdef CONFIG_ACPI_BUS /* - * "acpi_pic_sci=level" (current default) - * programs the PIC-mode SCI to Level Trigger. - * (NO-OP if the BIOS set Level Trigger already) + * acpi_pic_sci_set_trigger() + * + * use ELCR to set PIC-mode trigger type for SCI * - * If a PIC-mode SCI is not recogznied or gives spurious IRQ7's - * it may require Edge Trigger -- use "acpi_pic_sci=edge" - * (NO-OP if the BIOS set Edge Trigger already) + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_sci=edge" * * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. @@ -306,52 +367,32 @@ * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) */ -static __initdata int acpi_pic_sci_trigger; /* 0: level, 1: edge */ - void __init -acpi_pic_sci_set_trigger(unsigned int irq) +acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) { unsigned char mask = 1 << (irq & 7); unsigned int port = 0x4d0 + (irq >> 3); unsigned char val = inb(port); - + printk(PREFIX "IRQ%d SCI:", irq); if (!(val & mask)) { printk(" Edge"); - if (!acpi_pic_sci_trigger) { + if (trigger == 3) { printk(" set to Level"); outb(val | mask, port); } } else { printk(" Level"); - if (acpi_pic_sci_trigger) { + if (trigger == 1) { printk(" set to Edge"); - outb(val | mask, port); + outb(val & ~mask, port); } } printk(" Trigger.\n"); } - -int __init -acpi_pic_sci_setup(char *str) -{ - while (str && *str) { - if (strncmp(str, "level", 5) == 0) - acpi_pic_sci_trigger = 0; /* force level trigger */ - if (strncmp(str, "edge", 4) == 0) - acpi_pic_sci_trigger = 1; /* force edge trigger */ - str = strchr(str, ','); - if (str) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("acpi_pic_sci=", acpi_pic_sci_setup); - #endif /* CONFIG_ACPI_BUS */ static unsigned long __init @@ -412,7 +453,7 @@ */ result = acpi_table_init(); if (result) { - acpi_disabled = 1; + disable_acpi(); return result; } @@ -535,6 +576,9 @@ /* Build a default routing table for legacy (ISA) interrupts. */ mp_config_acpi_legacy_irqs(); + /* Record sci_int for use when looking for MADT sci_int override */ + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); @@ -542,6 +586,13 @@ return result; } + /* + * If BIOS did not supply an INT_SRC_OVR for the SCI + * pretend we got one so we can set the SCI flags. + */ + if (!acpi_sci_override_gsi) + acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); @@ -567,8 +618,6 @@ return 0; } -#endif /*CONFIG_ACPI_BOOT*/ - /* -------------------------------------------------------------------------- Low-Level Sleep Support diff -urN linux-2.4.25/arch/x86_64/kernel/aperture.c linux-2.4.26/arch/x86_64/kernel/aperture.c --- linux-2.4.25/arch/x86_64/kernel/aperture.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/arch/x86_64/kernel/aperture.c 2004-04-14 06:05:28.000000000 -0700 @@ -8,7 +8,7 @@ * because only the bootmem allocator can allocate 32+MB. * * Copyright 2002 Andi Kleen, SuSE Labs. - * $Id: aperture.c,v 1.7 2003/08/01 03:36:18 ak Exp $ + * $Id: aperture.c,v 1.8 2004/02/27 18:30:19 ak Exp $ */ #include #include @@ -27,6 +27,8 @@ int fallback_aper_order __initdata = 1; /* 64MB */ int fallback_aper_force __initdata = 0; +int iommu_aperture; + extern int no_iommu, force_mmu; /* This code runs before the PCI subsystem is initialized, so just @@ -198,6 +200,8 @@ if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) continue; + iommu_aperture = 1; + aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; aper_size = (32 * 1024 * 1024) << aper_order; aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff; diff -urN linux-2.4.25/arch/x86_64/kernel/e820.c linux-2.4.26/arch/x86_64/kernel/e820.c --- linux-2.4.25/arch/x86_64/kernel/e820.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/e820.c 2004-04-14 06:05:28.000000000 -0700 @@ -1,12 +1,13 @@ /* * Handle the memory map. * The functions here do the job until bootmem takes over. - * $Id: e820.c,v 1.12 2004/01/13 10:13:30 ak Exp $ + * $Id: e820.c,v 1.13 2004/03/22 00:31:08 ak Exp $ */ #include #include #include #include +#include #include #include #include @@ -21,6 +22,10 @@ extern unsigned long table_start, table_end; extern char _end[]; +#ifdef CONFIG_ACPI_BOOT +extern acpi_interrupt_flags acpi_sci_flags; +#endif + extern struct resource code_resource, data_resource, vram_resource; /* Check for some hardcoded bad areas that early boot is not allowed to touch */ @@ -541,12 +546,39 @@ iommu_setup(from+6); } #endif +#ifdef CONFIG_SMP + /* + * If the BIOS enumerates physical processors before logical, + * maxcpus=N at enumeration-time can be used to disable HT. + */ + else if (!memcmp(from, "maxcpus=", 8)) { + extern unsigned int max_cpus; + + max_cpus = simple_strtoul(from + 8, NULL, 0); + } +#endif + #ifdef CONFIG_ACPI_BOOT else if (!memcmp(from, "acpi=off", 8)) - acpi_disabled = 1; + disable_acpi(); + + /* acpi=strict disables out-of-spec workarounds */ + else if (!memcmp(from, "acpi=strict", 11)) { + acpi_strict = 1; + } + else if (!memcmp(from, "pci=noacpi", 10)) { acpi_noirq_set(); } + + else if (!memcmp(from, "acpi_sci=edge", 13)) + acpi_sci_flags.trigger = 1; + else if (!memcmp(from, "acpi_sci=level", 14)) + acpi_sci_flags.trigger = 3; + else if (!memcmp(from, "acpi_sci=high", 13)) + acpi_sci_flags.polarity = 1; + else if (!memcmp(from, "acpi_sci=low", 12)) + acpi_sci_flags.polarity = 3; #endif else if (!memcmp(from,"maxcpus=0",9)) { disable_ioapic_setup(); diff -urN linux-2.4.25/arch/x86_64/kernel/head.S linux-2.4.26/arch/x86_64/kernel/head.S --- linux-2.4.25/arch/x86_64/kernel/head.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/head.S 2004-04-14 06:05:28.000000000 -0700 @@ -6,7 +6,7 @@ * Copyright (C) 2000 Karsten Keil * Copyright (C) 2001,2002 Andi Kleen * - * $Id: head.S,v 1.58 2003/11/02 05:05:31 ak Exp $ + * $Id: head.S,v 1.59 2004/02/10 05:53:06 ak Exp $ */ @@ -341,7 +341,7 @@ .align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */ ENTRY(gdt_table) .quad 0x0000000000000000 /* This one is magic */ - .quad 0x00af9a000000ffff ^ (1<<21) /* __KERNEL_COMPAT32_CS */ + .quad 0x008f9a000000ffff /* __KERNEL_COMPAT32_CS */ .quad 0x00af9a000000ffff /* __KERNEL_CS */ .quad 0x00cf92000000ffff /* __KERNEL_DS */ .quad 0x00cffe000000ffff /* __USER32_CS */ diff -urN linux-2.4.25/arch/x86_64/kernel/io_apic.c linux-2.4.26/arch/x86_64/kernel/io_apic.c --- linux-2.4.25/arch/x86_64/kernel/io_apic.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/io_apic.c 2004-04-14 06:05:28.000000000 -0700 @@ -1850,7 +1850,11 @@ entry.trigger = edge_level; entry.polarity = active_high_low; - add_pin_to_irq(irq, ioapic, pin); + /* + * IRQs < 16 are already in the irq_2_pin[] map + */ + if (irq >= 16) + add_pin_to_irq(irq, ioapic, pin); entry.vector = assign_irq_vector(irq); diff -urN linux-2.4.25/arch/x86_64/kernel/mpparse.c linux-2.4.26/arch/x86_64/kernel/mpparse.c --- linux-2.4.25/arch/x86_64/kernel/mpparse.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/mpparse.c 2004-04-14 06:05:28.000000000 -0700 @@ -35,6 +35,9 @@ /* Have we found an MP table */ int smp_found_config = 0; +#ifdef CONFIG_SMP +extern unsigned int max_cpus; +#endif /* * Various Linux-internal data structures created from the @@ -111,6 +114,20 @@ Dprintk(" Bootup CPU\n"); boot_cpu_id = m->mpc_apicid; } + +#ifdef CONFIG_SMP + if (num_processors >= NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processor ignored.\n", NR_CPUS); + return; + } + if (num_processors >= max_cpus) { + printk(KERN_WARNING "WARNING: maxcpus limit of %i reached." + " Processor ignored.\n", max_cpus); + return; + } +#endif + num_processors++; if (m->mpc_apicid > MAX_APICS) { @@ -794,7 +811,7 @@ * erroneously sets the trigger to level, resulting in a HUGE * increase of timer interrupts! */ - if ((bus_irq == 0) && (global_irq == 2) && (trigger == 3)) + if ((bus_irq == 0) && (trigger == 3)) trigger = 1; intsrc.mpc_type = MP_INTSRC; @@ -815,7 +832,7 @@ * Otherwise create a new entry (e.g. global_irq == 2). */ for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) + if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) && (mp_irqs[i].mpc_dstirq == intsrc.mpc_dstirq)) { mp_irqs[i] = intsrc; found = 1; @@ -862,9 +879,10 @@ */ for (i = 0; i < 16; i++) { - if (i == 2) continue; /* Don't connect IRQ2 */ + if (i == 2) + continue; /* Don't connect IRQ2 */ - intsrc.mpc_irqtype = i ? mp_INT : mp_ExtINT; /* 8259A to #0 */ + intsrc.mpc_irqtype = mp_INT; intsrc.mpc_srcbusirq = i; /* Identity mapped */ intsrc.mpc_dstirq = i; @@ -888,63 +906,6 @@ extern FADT_DESCRIPTOR acpi_fadt; -void __init mp_config_ioapic_for_sci(int irq) -{ - int ioapic; - int ioapic_pin; - struct acpi_table_madt* madt; - struct acpi_table_int_src_ovr *entry = NULL; - acpi_interrupt_flags flags; - void *madt_end; - acpi_status status; - - /* - * Ensure that if there is an interrupt source override entry - * for the ACPI SCI, we leave it as is. Unfortunately this involves - * walking the MADT again. - */ - status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) &madt); - if (ACPI_SUCCESS(status)) { - madt_end = (void *) (unsigned long)madt + madt->header.length; - - entry = (struct acpi_table_int_src_ovr *) - ((unsigned long) madt + sizeof(struct acpi_table_madt)); - - while ((void *) entry < madt_end) { - if (entry->header.type == ACPI_MADT_INT_SRC_OVR && - acpi_fadt.sci_int == entry->bus_irq) - goto found; - - entry = (struct acpi_table_int_src_ovr *) - ((unsigned long) entry + entry->header.length); - } - } - /* - * Although the ACPI spec says that the SCI should be level/low - * don't reprogram it unless there is an explicit MADT OVR entry - * instructing us to do so -- otherwise we break Tyan boards which - * have the SCI wired edge/high but no MADT OVR. - */ - return; - -found: - /* - * See the note at the end of ACPI 2.0b section - * 5.2.10.8 for what this is about. - */ - flags = entry->flags; - acpi_fadt.sci_int = entry->global_irq; - irq = entry->global_irq; - - ioapic = mp_find_ioapic(irq); - - ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - - io_apic_set_pci_routing(ioapic, ioapic_pin, irq, - (flags.trigger >> 1) , (flags.polarity >> 1)); -} - #endif /*CONFIG_ACPI_HT_ONLY*/ int acpi_tolerant; @@ -1008,7 +969,7 @@ continue; } if ((1<irq = irq; continue; diff -urN linux-2.4.25/arch/x86_64/kernel/mtrr.c linux-2.4.26/arch/x86_64/kernel/mtrr.c --- linux-2.4.25/arch/x86_64/kernel/mtrr.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/mtrr.c 2004-04-14 06:05:28.000000000 -0700 @@ -144,11 +144,14 @@ write_cr0(cr0); wbinvd(); - /* Disable MTRRs, and set the default type to uncached */ rdmsr(MSR_MTRRdefType, ctxt->deftype_lo, ctxt->deftype_hi); - wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); } +static void set_mtrr_disable(struct set_mtrr_context *ctxt) +{ + /* Disable MTRRs, and set the default type to uncached */ + wrmsr(MSR_MTRRdefType, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); +} /* Restore the processor after a set_mtrr_prepare */ static void set_mtrr_done (struct set_mtrr_context *ctxt) @@ -242,8 +245,10 @@ u64 base64; u64 size64; - if (do_safe) + if (do_safe) { set_mtrr_prepare (&ctxt); + set_mtrr_disable (&ctxt); + } if (size == 0) { /* The invalid bit is kept in the mask, so we simply clear the @@ -430,6 +435,7 @@ static atomic_t undone_count; +static volatile int wait_barrier_mtrr_disable = FALSE; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; @@ -451,8 +457,18 @@ set_mtrr_prepare (&ctxt); /* Notify master that I've flushed and disabled my cache */ atomic_dec (&undone_count); - while (wait_barrier_execute) + + while (wait_barrier_mtrr_disable) { + rep_nop(); barrier (); + } + set_mtrr_disable (&ctxt); + /* wait again for disable confirmation*/ + atomic_dec (&undone_count); + while (wait_barrier_execute) { + rep_nop(); + barrier(); + } /* The master has cleared me to execute */ set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, @@ -462,8 +478,10 @@ atomic_dec (&undone_count); /* Wait for master to clear me to enable cache and return */ - while (wait_barrier_cache_enable) + while (wait_barrier_cache_enable) { + rep_nop(); barrier (); + } set_mtrr_done (&ctxt); } @@ -479,6 +497,7 @@ data.smp_type = type; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; + wait_barrier_mtrr_disable = TRUE; atomic_set (&undone_count, smp_num_cpus - 1); /* Start the ball rolling on other CPUs */ @@ -487,10 +506,21 @@ /* Flush and disable the local CPU's cache */ set_mtrr_prepare (&ctxt); + while (atomic_read (&undone_count) > 0) { + rep_nop(); + barrier(); + } + + /* Set up for completion wait and then release other CPUs to change MTRRs*/ + atomic_set (&undone_count, smp_num_cpus - 1); + wait_barrier_mtrr_disable = FALSE; + set_mtrr_disable (&ctxt); /* Wait for all other CPUs to flush and disable their caches */ - while (atomic_read (&undone_count) > 0) + while (atomic_read (&undone_count) > 0) { + rep_nop (); barrier (); + } /* Set up for completion wait and then release other CPUs to change MTRRs */ atomic_set (&undone_count, smp_num_cpus - 1); @@ -498,8 +528,10 @@ set_mtrr_up (reg, base, size, type, FALSE); /* Now wait for other CPUs to complete the function */ - while (atomic_read (&undone_count) > 0) + while (atomic_read (&undone_count) > 0) { + rep_nop(); barrier (); + } /* Now all CPUs should have finished the function. Release the barrier to allow them to re-enable their caches and return from their interrupt, @@ -1282,6 +1314,7 @@ for this CPU while the MTRRs are changed, but changing this requires more invasive changes to the way the kernel boots */ set_mtrr_prepare (&ctxt); + set_mtrr_disable (&ctxt); mask = set_mtrr_state (&smp_mtrr_state, &ctxt); set_mtrr_done (&ctxt); diff -urN linux-2.4.25/arch/x86_64/kernel/nmi.c linux-2.4.26/arch/x86_64/kernel/nmi.c --- linux-2.4.25/arch/x86_64/kernel/nmi.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/nmi.c 2004-04-14 06:05:28.000000000 -0700 @@ -34,6 +34,13 @@ int nmi_watchdog_disabled; +/* Small problem with theaw events is that they stop ticking + when the CPU is idling. This means you get varying NMI watchdog + frequencies depending on the CPU load. + + I doubt it can be fixed because it's unlikely that the CPU does + performance counters while being in C* states. -AK */ + #define K7_EVNTSEL_ENABLE (1 << 22) #define K7_EVNTSEL_INT (1 << 20) #define K7_EVNTSEL_OS (1 << 17) @@ -215,6 +222,11 @@ { unsigned int evntsel; +#if 0 + /* No check, so can start with slow frequency */ + nmi_hz = 1; +#endif + nmi_perfctr_msr = MSR_K7_PERFCTR0; clear_msr_range(MSR_K7_EVNTSEL0, 4); diff -urN linux-2.4.25/arch/x86_64/kernel/pci-gart.c linux-2.4.26/arch/x86_64/kernel/pci-gart.c --- linux-2.4.25/arch/x86_64/kernel/pci-gart.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/pci-gart.c 2004-04-14 06:05:28.000000000 -0700 @@ -8,7 +8,7 @@ * See Documentation/DMA-mapping.txt for the interface specification. * * Copyright 2002 Andi Kleen, SuSE Labs. - * $Id: pci-gart.c,v 1.30 2004/01/13 09:09:32 ak Exp $ + * $Id: pci-gart.c,v 1.32 2004/02/27 18:30:19 ak Exp $ */ #include @@ -220,7 +220,7 @@ unsigned long iommu_page; size = round_up(size, PAGE_SIZE); - if (bus >= iommu_bus_base && bus <= iommu_bus_base + iommu_size) { + if (bus >= iommu_bus_base && bus < iommu_bus_base + iommu_size) { unsigned pages = size >> PAGE_SHIFT; iommu_page = (bus - iommu_bus_base) >> PAGE_SHIFT; vaddr = __va(GPTE_DECODE(iommu_gatt_base[iommu_page])); @@ -310,6 +310,12 @@ BUG_ON(dir == PCI_DMA_NONE); +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_map_single(dev,addr,size,dir); +#endif + + phys_mem = virt_to_phys(addr); if (!need_iommu(dev, phys_mem, size)) return phys_mem; @@ -352,8 +358,17 @@ { unsigned long iommu_page; int npages; + +#ifdef CONFIG_SWIOTLB + if (swiotlb) { + swiotlb_unmap_single(hwdev,dma_addr,size,direction); + return; + } +#endif + + if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || - dma_addr > iommu_bus_base + iommu_size) + dma_addr >= iommu_bus_base + iommu_size) return; iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; npages = round_up(size + (dma_addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT; @@ -488,7 +503,14 @@ no_agp = no_agp || (agp_init() < 0) || (agp_copy_info(&info) < 0); #endif - if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT)) { + if (swiotlb) { + no_iommu = 1; + printk(KERN_INFO "PCI-DMA: Using SWIOTLB\n"); + return; + } + + + if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT) || !iommu_aperture) { printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); no_iommu = 1; return; diff -urN linux-2.4.25/arch/x86_64/kernel/pci-pc.c linux-2.4.26/arch/x86_64/kernel/pci-pc.c --- linux-2.4.25/arch/x86_64/kernel/pci-pc.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/pci-pc.c 2004-04-14 06:05:28.000000000 -0700 @@ -645,6 +645,9 @@ } else if (!strncmp(str, "lastbus=", 8)) { pcibios_last_bus = simple_strtol(str+8, NULL, 0); return NULL; + } else if (!strncmp(str, "noacpi", 6)) { + acpi_noirq_set(); + return NULL; } return str; } diff -urN linux-2.4.25/arch/x86_64/kernel/process.c linux-2.4.26/arch/x86_64/kernel/process.c --- linux-2.4.25/arch/x86_64/kernel/process.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/process.c 2004-04-14 06:05:28.000000000 -0700 @@ -9,7 +9,7 @@ * X86-64 port * Andi Kleen. * - * $Id: process.c,v 1.75 2004/01/13 09:04:32 ak Exp $ + * $Id: process.c,v 1.77 2004/03/22 00:37:29 ak Exp $ */ /* @@ -147,11 +147,57 @@ } } +/* + * This is a kind of hybrid between poll and halt idle routines. This uses new + * Monitor/Mwait instructions on P4 processors with PNI. We Monitor + * need_resched and go to optimized wait state through Mwait. + * Whenever someone changes need_resched, we would be woken up from Mwait + * (without an IPI). + */ +static void mwait_idle (void) +{ + int oldval; + + __sti(); + /* Setting need_resched to -1 skips sending IPI during idle resched */ + oldval = xchg(¤t->need_resched, -1); + if (!oldval) { + do { + __monitor((void *)¤t->need_resched, 0, 0); + if (current->need_resched != -1) + break; + __mwait(0, 0); + } while (current->need_resched == -1); + } +} + +int __init select_idle_routine(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_MWAIT)) { + printk("Monitor/Mwait feature present.\n"); + /* + * Take care of system with asymmetric CPUs. + * Use, mwait_idle only if all cpus support it. + * If not, we fallback to default_idle() + */ + if (!pm_idle) { + pm_idle = mwait_idle; + } + return 1; + } + pm_idle = default_idle; + return 1; +} + + static int __init idle_setup (char *str) { if (!strncmp(str, "poll", 4)) { printk("using polling idle threads.\n"); pm_idle = poll_idle; + } else if (!strncmp(str, "halt", 4)) { + printk("using halt in idle threads.\n"); + pm_idle = default_idle; } return 1; @@ -301,7 +347,7 @@ /* force cold reboot to reinit all hardware*/ *((unsigned short *)__va(0x472)) = 0; - __asm__ __volatile__("lidt %0": :"m" (no_idt)); + __asm__ __volatile__("lidt (%0)": :"r" (no_idt)); __asm__ __volatile__("int3"); reboot_type = BOOT_KBD; diff -urN linux-2.4.25/arch/x86_64/kernel/setup.c linux-2.4.26/arch/x86_64/kernel/setup.c --- linux-2.4.25/arch/x86_64/kernel/setup.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/setup.c 2004-04-14 06:05:28.000000000 -0700 @@ -54,6 +54,10 @@ #endif +int swiotlb; + +extern int phys_proc_id[NR_CPUS]; + /* * Machine setup.. */ @@ -228,6 +232,8 @@ e820_end_of_ram(); + check_efer(); + init_memory_mapping(); #ifdef CONFIG_BLK_DEV_INITRD @@ -308,8 +314,7 @@ /* * Parse the ACPI tables for possible boot-time SMP configuration. */ - if (!acpi_disabled) - acpi_boot_init(); + acpi_boot_init(); #endif #ifdef CONFIG_X86_LOCAL_APIC /* @@ -341,6 +346,12 @@ #ifdef CONFIG_GART_IOMMU iommu_hole_init(); #endif +#ifdef CONFIG_SWIOTLB + if (!iommu_aperture && end_pfn >= 0xffffffff>>PAGE_SHIFT) { + swiotlb_init(); + swiotlb = 1; + } +#endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -404,6 +415,198 @@ } } +#define LVL_1_INST 1 +#define LVL_1_DATA 2 +#define LVL_2 3 +#define LVL_3 4 +#define LVL_TRACE 5 + +struct _cache_table +{ + unsigned char descriptor; + char cache_type; + short size; +}; + +/* all the cache descriptor types we care about (no TLB or trace cache entries) */ +static struct _cache_table cache_table[] __initdata = +{ + { 0x06, LVL_1_INST, 8 }, + { 0x08, LVL_1_INST, 16 }, + { 0x0A, LVL_1_DATA, 8 }, + { 0x0C, LVL_1_DATA, 16 }, + { 0x22, LVL_3, 512 }, + { 0x23, LVL_3, 1024 }, + { 0x25, LVL_3, 2048 }, + { 0x29, LVL_3, 4096 }, + { 0x39, LVL_2, 128 }, + { 0x3C, LVL_2, 256 }, + { 0x41, LVL_2, 128 }, + { 0x42, LVL_2, 256 }, + { 0x43, LVL_2, 512 }, + { 0x44, LVL_2, 1024 }, + { 0x45, LVL_2, 2048 }, + { 0x66, LVL_1_DATA, 8 }, + { 0x67, LVL_1_DATA, 16 }, + { 0x68, LVL_1_DATA, 32 }, + { 0x70, LVL_TRACE, 12 }, + { 0x71, LVL_TRACE, 16 }, + { 0x72, LVL_TRACE, 32 }, + { 0x79, LVL_2, 128 }, + { 0x7A, LVL_2, 256 }, + { 0x7B, LVL_2, 512 }, + { 0x7C, LVL_2, 1024 }, + { 0x82, LVL_2, 256 }, + { 0x83, LVL_2, 512 }, + { 0x84, LVL_2, 1024 }, + { 0x85, LVL_2, 2048 }, + { 0x00, 0, 0} +}; + +int select_idle_routine(struct cpuinfo_x86 *c); + +static void __init init_intel(struct cpuinfo_x86 *c) +{ + unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ + char *p = NULL; + u32 eax, dummy; + + unsigned int n; + + + select_idle_routine(c); + if (c->cpuid_level > 1) { + /* supports eax=2 call */ + int i, j, n; + int regs[4]; + unsigned char *dp = (unsigned char *)regs; + + /* Number of times to iterate */ + n = cpuid_eax(2) & 0xFF; + + for ( i = 0 ; i < n ; i++ ) { + cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]); + + /* If bit 31 is set, this is an unknown format */ + for ( j = 0 ; j < 3 ; j++ ) { + if ( regs[j] < 0 ) regs[j] = 0; + } + + /* Byte 0 is level count, not a descriptor */ + for ( j = 1 ; j < 16 ; j++ ) { + unsigned char des = dp[j]; + unsigned char k = 0; + + /* look up this descriptor in the table */ + while (cache_table[k].descriptor != 0) + { + if (cache_table[k].descriptor == des) { + switch (cache_table[k].cache_type) { + case LVL_1_INST: + l1i += cache_table[k].size; + break; + case LVL_1_DATA: + l1d += cache_table[k].size; + break; + case LVL_2: + l2 += cache_table[k].size; + break; + case LVL_3: + l3 += cache_table[k].size; + break; + case LVL_TRACE: + trace += cache_table[k].size; + break; + } + break; + } + + k++; + } + } + } + + if ( trace ) + printk (KERN_INFO "CPU: Trace cache: %dK uops", trace); + else if ( l1i ) + printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); + if ( l1d ) + printk(", L1 D cache: %dK\n", l1d); + else + printk("\n"); + if ( l2 ) + printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); + if ( l3 ) + printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); + + /* + * This assumes the L3 cache is shared; it typically lives in + * the northbridge. The L1 caches are included by the L2 + * cache, and so should not be included for the purpose of + * SMP switching weights. + */ + c->x86_cache_size = l2 ? l2 : (l1i+l1d); + } + + if ( p ) + strcpy(c->x86_model_id, p); + +#ifdef CONFIG_SMP + if (test_bit(X86_FEATURE_HT, &c->x86_capability)) { + int index_lsb, index_msb, tmp; + int initial_apic_id; + int cpu = smp_processor_id(); + u32 ebx, ecx, edx; + + cpuid(1, &eax, &ebx, &ecx, &edx); + smp_num_siblings = (ebx & 0xff0000) >> 16; + + if (smp_num_siblings == 1) { + printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); + } else if (smp_num_siblings > 1 ) { + index_lsb = 0; + index_msb = 31; + /* + * At this point we only support two siblings per + * processor package. + */ +#define NR_SIBLINGS 2 + if (smp_num_siblings != NR_SIBLINGS) { + printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings); + smp_num_siblings = 1; + return; + } + tmp = smp_num_siblings; + while ((tmp & 1) == 0) { + tmp >>=1 ; + index_lsb++; + } + tmp = smp_num_siblings; + while ((tmp & 0x80000000 ) == 0) { + tmp <<=1 ; + index_msb--; + } + if (index_lsb != index_msb ) + index_msb++; + initial_apic_id = ebx >> 24 & 0xff; + phys_proc_id[cpu] = initial_apic_id >> index_msb; + + printk(KERN_INFO "CPU: Physical Processor ID: %d\n", + phys_proc_id[cpu]); + } + + } +#endif + + n = cpuid_eax(0x80000000); + if (n >= 0x80000008) { + cpuid(0x80000008, &eax, &dummy, &dummy, &dummy); + c->x86_virt_bits = (eax >> 8) & 0xff; + c->x86_phys_bits = eax & 0xff; + } + +} + static int __init init_amd(struct cpuinfo_x86 *c) { int r; @@ -433,6 +636,8 @@ if (!strcmp(v, "AuthenticAMD")) c->x86_vendor = X86_VENDOR_AMD; + else if (!strcmp(v, "GenuineIntel")) + c->x86_vendor = X86_VENDOR_INTEL; else c->x86_vendor = X86_VENDOR_UNKNOWN; } @@ -448,7 +653,7 @@ */ void __init identify_cpu(struct cpuinfo_x86 *c) { - int junk, i; + int i; u32 xlvl, tfms; c->loops_per_jiffy = loops_per_jiffy; @@ -472,7 +677,7 @@ /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { __u32 misc; - cpuid(0x00000001, &tfms, &misc, &junk, + cpuid(0x00000001, &tfms, &misc, &c->x86_capability[4], &c->x86_capability[0]); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; @@ -521,9 +726,12 @@ init_amd(c); break; + case X86_VENDOR_INTEL: + init_intel(c); + break; case X86_VENDOR_UNKNOWN: default: - /* Not much we can do here... */ + display_cacheinfo(c); break; } @@ -581,7 +789,7 @@ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx", - "fxsr", "sse", "sse2", "ss", NULL, "tm", "ia64", NULL, + "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe", /* AMD-defined */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -600,6 +808,12 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /* Intel Defined (cpuid 1 and ecx) */ + "pni", NULL, NULL, "monitor", "ds-cpl", NULL, NULL, "est", + "tm2", NULL, "cid", NULL, NULL, "cmpxchg16b", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static char *x86_power_flags[] = { "ts", /* temperature sensor */ @@ -636,6 +850,11 @@ seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); +#ifdef CONFIG_SMP + seq_printf(m, "physical id\t: %d\n",phys_proc_id[c - cpu_data]); + seq_printf(m, "siblings\t: %d\n",smp_num_siblings); +#endif + seq_printf(m, "fpu\t\t: yes\n" "fpu_exception\t: yes\n" @@ -660,6 +879,7 @@ seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize); seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size); + if (c->x86_phys_bits > 0) seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", c->x86_phys_bits, c->x86_virt_bits); diff -urN linux-2.4.25/arch/x86_64/kernel/setup64.c linux-2.4.26/arch/x86_64/kernel/setup64.c --- linux-2.4.25/arch/x86_64/kernel/setup64.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/setup64.c 2004-04-14 06:05:28.000000000 -0700 @@ -3,7 +3,7 @@ * Copyright (C) 1995 Linus Torvalds * Copyright 2001, 2002 SuSE Labs / Andi Kleen. * See setup.c for older changelog. - * $Id: setup64.c,v 1.26 2003/10/15 01:32:42 ak Exp $ + * $Id: setup64.c,v 1.27 2004/02/27 18:30:19 ak Exp $ */ #include #include @@ -160,6 +160,17 @@ char boot_exception_stacks[N_EXCEPTION_STACKS*EXCEPTION_STKSZ]; +void check_efer(void) +{ + unsigned long efer; + rdmsrl(MSR_EFER, efer); + if (!(efer & EFER_NX) || do_not_nx) { + __supported_pte_mask &= ~_PAGE_NX; + } else { + __supported_pte_mask |= _PAGE_NX; + } +} + /* * cpu_init() initializes state that is per-CPU. Some data is already * initialized (naturally) in the bootstrap process, such as the GDT @@ -175,7 +186,7 @@ int nr = smp_processor_id(); #endif struct tss_struct * t = &init_tss[nr]; - unsigned long v, efer; + unsigned long v; unsigned long estack; /* CPU 0 is initialised in head64.c */ @@ -202,12 +213,7 @@ syscall_init(); - rdmsrl(MSR_EFER, efer); - if (!(efer & EFER_NX) || do_not_nx) { - __supported_pte_mask &= ~_PAGE_NX; - } else { - __supported_pte_mask |= _PAGE_NX; - } + check_efer(); t->io_map_base = INVALID_IO_BITMAP_OFFSET; memset(t->io_bitmap, 0xff, sizeof(t->io_bitmap)); diff -urN linux-2.4.25/arch/x86_64/kernel/smpboot.c linux-2.4.26/arch/x86_64/kernel/smpboot.c --- linux-2.4.25/arch/x86_64/kernel/smpboot.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/smpboot.c 2004-04-14 06:05:28.000000000 -0700 @@ -53,13 +53,18 @@ #include /* Setup configured maximum number of CPUs to activate */ -static int max_cpus = -1; +unsigned int max_cpus = NR_CPUS; static int cpu_mask = -1; /* Total count of live CPUs */ int smp_num_cpus = 1; +/* Number of siblings per CPU package */ +int smp_num_siblings = 1; +int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ +int cpu_sibling_map[NR_CPUS] __cacheline_aligned; + /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -84,10 +89,6 @@ * * Command-line option of "nosmp" or "maxcpus=0" will disable SMP * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . */ static int __init nosmp(char *str) @@ -98,15 +99,6 @@ __setup("nosmp", nosmp); -static int __init maxcpus(char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); - - static int __init cpumask(char *str) { get_option(&str, &cpu_mask); @@ -936,8 +928,6 @@ continue; if (((1<= 0) && (max_cpus <= cpucount+1)) - continue; cpu = do_boot_cpu(apicid); @@ -992,6 +982,34 @@ Dprintk("Boot done.\n"); /* + * If Hyper-Threading is avaialble, construct cpu_sibling_map[], so + * that we can tell the sibling CPU efficiently. + */ + if (test_bit(X86_FEATURE_HT, boot_cpu_data.x86_capability) + && smp_num_siblings > 1) { + for (cpu = 0; cpu < NR_CPUS; cpu++) + cpu_sibling_map[cpu] = NO_PROC_ID; + + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + int i; + + for (i = 0; i < smp_num_cpus; i++) { + if (i == cpu) + continue; + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_sibling_map[cpu] = i; + printk("cpu_sibling_map[%d] = %d\n", cpu, cpu_sibling_map[cpu]); + break; + } + } + if (cpu_sibling_map[cpu] == NO_PROC_ID) { + smp_num_siblings = 1; + printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu); + } + } + } + + /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ diff -urN linux-2.4.25/arch/x86_64/kernel/swiotlb.c linux-2.4.26/arch/x86_64/kernel/swiotlb.c --- linux-2.4.25/arch/x86_64/kernel/swiotlb.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/swiotlb.c 2004-04-14 06:05:28.000000000 -0700 @@ -0,0 +1 @@ +#include "../../ia64/lib/swiotlb.c" diff -urN linux-2.4.25/arch/x86_64/kernel/traps.c linux-2.4.26/arch/x86_64/kernel/traps.c --- linux-2.4.25/arch/x86_64/kernel/traps.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/traps.c 2004-04-14 06:05:28.000000000 -0700 @@ -7,7 +7,7 @@ * Pentium III FXSR, SSE support * Gareth Hughes , May 2000 * - * $Id: traps.c,v 1.69 2003/09/21 04:54:09 ak Exp $ + * $Id: traps.c,v 1.71 2004/02/27 22:07:36 ak Exp $ */ /* diff -urN linux-2.4.25/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.26/arch/x86_64/kernel/x8664_ksyms.c --- linux-2.4.25/arch/x86_64/kernel/x8664_ksyms.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/kernel/x8664_ksyms.c 2004-04-14 06:05:28.000000000 -0700 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,7 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); +EXPORT_SYMBOL(sys_ioctl); #ifdef CONFIG_IO_DEBUG EXPORT_SYMBOL(__io_virt_debug); diff -urN linux-2.4.25/arch/x86_64/lib/copy_page.S linux-2.4.26/arch/x86_64/lib/copy_page.S --- linux-2.4.25/arch/x86_64/lib/copy_page.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/lib/copy_page.S 2004-04-14 06:05:28.000000000 -0700 @@ -1,5 +1,7 @@ /* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */ +#include + /* Don't use streaming store because it's better when the target ends up in cache. */ @@ -8,10 +10,13 @@ .globl copy_page .p2align 4 copy_page: - prefetch (%rsi) - prefetch 1*64(%rsi) + + prefetcht0 (%rsi) + prefetcht0 1*64(%rsi) +#ifdef CONFIG_MK8 prefetchw (%rdi) prefetchw 1*64(%rdi) +#endif subq $3*8,%rsp movq %rbx,(%rsp) @@ -32,7 +37,7 @@ movq 48 (%rsi), %r11 movq 56 (%rsi), %r12 - prefetch 5*64(%rsi) + prefetcht0 5*64(%rsi) movq %rax, (%rdi) movq %rbx, 8 (%rdi) @@ -43,7 +48,9 @@ movq %r11, 48 (%rdi) movq %r12, 56 (%rdi) +#ifdef CONFIG_MK8 prefetchw 5*64(%rdi) +#endif leaq 64 (%rsi), %rsi leaq 64 (%rdi), %rdi diff -urN linux-2.4.25/arch/x86_64/lib/copy_user.S linux-2.4.26/arch/x86_64/lib/copy_user.S --- linux-2.4.25/arch/x86_64/lib/copy_user.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/lib/copy_user.S 2004-04-14 06:05:28.000000000 -0700 @@ -4,6 +4,8 @@ * Functions to copy from and to user space. */ + #include + /* #define FIX_ALIGNMENT 1 */ #include @@ -59,8 +61,10 @@ .globl copy_user_generic .p2align 4 copy_user_generic: - prefetch (%rsi) + prefetcht0 (%rsi) +#ifdef CONFIG_MK8 prefetchw (%rdi) +#endif pushq %rbx xorl %eax,%eax /*zero for the exception handler */ diff -urN linux-2.4.25/arch/x86_64/lib/csum-copy.S linux-2.4.26/arch/x86_64/lib/csum-copy.S --- linux-2.4.25/arch/x86_64/lib/csum-copy.S 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/lib/csum-copy.S 2004-04-14 06:05:28.000000000 -0700 @@ -44,32 +44,9 @@ .previous .endm - .macro ignore L=.Lignore -30: - .section __ex_table,"a" - .align 8 - .quad 30b,\L - .previous - .endm - - .globl csum_partial_copy_generic .p2align 4 csum_partial_copy_generic: - cmpl $2*64,%edx - jle .Lignore - - ignore - prefetch 1*64(%rdi) - ignore - prefetch 2*64(%rdi) - ignore - prefetchw (%rsi) - ignore - prefetchw 1*64(%rsi) - ignore - -.Lignore: subq $7*8,%rsp movq %rbx,2*8(%rsp) movq %r12,3*8(%rsp) diff -urN linux-2.4.25/arch/x86_64/lib/csum-partial.c linux-2.4.26/arch/x86_64/lib/csum-partial.c --- linux-2.4.25/arch/x86_64/lib/csum-partial.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.26/arch/x86_64/lib/csum-partial.c 2004-04-14 06:05:28.000000000 -0700 @@ -136,11 +136,10 @@ } /* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c + * this routine is used for miscellaneous IP-like checksums. */ unsigned short ip_compute_csum(unsigned char * buff, int len) { - return ~csum_partial(buff,len,0); + return csum_fold(csum_partial(buff,len,0)); } diff -urN linux-2.4.25/arch/x86_64/lib/usercopy.c linux-2.4.26/arch/x86_64/lib/usercopy.c --- linux-2.4.25/arch/x86_64/lib/usercopy.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/lib/usercopy.c 2004-04-14 06:05:28.000000000 -0700 @@ -126,3 +126,11 @@ s++; } } + +unsigned long copy_in_user(void *to, const void *from, unsigned len) +{ + if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { + return copy_user_generic(to, from, len); + } + return len; +} diff -urN linux-2.4.25/arch/x86_64/mm/fault.c linux-2.4.26/arch/x86_64/mm/fault.c --- linux-2.4.25/arch/x86_64/mm/fault.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/arch/x86_64/mm/fault.c 2004-04-14 06:05:28.000000000 -0700 @@ -327,7 +327,8 @@ regs->rsp, error_code); tsk->thread.cr2 = address; - tsk->thread.error_code = error_code; + /* Kernel addresses are always protection faults */ + tsk->thread.error_code = error_code | (address >= TASK_SIZE); tsk->thread.trap_no = 14; info.si_signo = SIGSEGV; info.si_errno = 0; diff -urN linux-2.4.25/arch/x86_64/mm/k8topology.c linux-2.4.26/arch/x86_64/mm/k8topology.c --- linux-2.4.25/arch/x86_64/mm/k8topology.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/arch/x86_64/mm/k8topology.c 2004-04-14 06:05:28.000000000 -0700 @@ -197,7 +197,7 @@ continue; if ((nodes_present >> rr) == 0) rr = 0; - rr = ffz(~nodes_present >> rr); + rr += ffz(~nodes_present >> rr); PLAT_NODE_DATA(i) = PLAT_NODE_DATA(rr); rr++; } diff -urN linux-2.4.25/arch/x86_64/mm/pageattr.c linux-2.4.26/arch/x86_64/mm/pageattr.c --- linux-2.4.25/arch/x86_64/mm/pageattr.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.26/arch/x86_64/mm/pageattr.c 2004-04-14 06:05:28.000000000 -0700 @@ -52,7 +52,7 @@ /* is this worth it? */ int i; for (i = 0; i < PAGE_SIZE; i += cpu->x86_clflush_size) - asm volatile("clflush %0" :: "m" (address + i)); + asm volatile("clflush (%0)" :: "r" (address + i)); } else asm volatile("wbinvd":::"memory"); __flush_tlb_one(address); diff -urN linux-2.4.25/crypto/Config.in linux-2.4.26/crypto/Config.in --- linux-2.4.25/crypto/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/crypto/Config.in 2004-04-14 06:05:28.000000000 -0700 @@ -72,6 +72,7 @@ tristate ' AES cipher algorithms' CONFIG_CRYPTO_AES tristate ' CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5 tristate ' CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6 + tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4 if [ "$CONFIG_INET_IPCOMP" = "y" -o \ "$CONFIG_INET_IPCOMP" = "m" -o \ "$CONFIG_INET6_IPCOMP" = "y" -o \ diff -urN linux-2.4.25/crypto/Makefile linux-2.4.26/crypto/Makefile --- linux-2.4.25/crypto/Makefile 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/crypto/Makefile 2004-04-14 06:05:28.000000000 -0700 @@ -9,7 +9,7 @@ autoload-crypto-$(CONFIG_KMOD) = autoload.o proc-crypto-$(CONFIG_PROC_FS) = proc.o -obj-$(CONFIG_CRYPTO) += api.o cipher.o digest.o compress.o \ +obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o \ $(autoload-crypto-y) $(proc-crypto-y) obj-$(CONFIG_CRYPTO_HMAC) += hmac.o @@ -26,6 +26,7 @@ obj-$(CONFIG_CRYPTO_AES) += aes.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o +obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff -urN linux-2.4.25/crypto/arc4.c linux-2.4.26/crypto/arc4.c --- linux-2.4.25/crypto/arc4.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/crypto/arc4.c 2004-04-14 06:05:28.000000000 -0700 @@ -0,0 +1,103 @@ +/* + * Cryptographic API + * + * ARC4 Cipher Algorithm + * + * Jon Oberheide + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ +#include +#include +#include + +#define ARC4_MIN_KEY_SIZE 1 +#define ARC4_MAX_KEY_SIZE 256 +#define ARC4_BLOCK_SIZE 1 + +struct arc4_ctx { + u8 S[256]; + u8 x, y; +}; + +static int arc4_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, u32 *flags) +{ + struct arc4_ctx *ctx = ctx_arg; + int i, j = 0, k = 0; + + ctx->x = 1; + ctx->y = 0; + + for(i = 0; i < 256; i++) + ctx->S[i] = i; + + for(i = 0; i < 256; i++) + { + u8 a = ctx->S[i]; + j = (j + in_key[k] + a) & 0xff; + ctx->S[i] = ctx->S[j]; + ctx->S[j] = a; + if(++k >= key_len) + k = 0; + } + + return 0; +} + +static void arc4_crypt(void *ctx_arg, u8 *out, const u8 *in) +{ + struct arc4_ctx *ctx = ctx_arg; + + u8 *const S = ctx->S; + u8 x = ctx->x; + u8 y = ctx->y; + u8 a, b; + + a = S[x]; + y = (y + a) & 0xff; + b = S[y]; + S[x] = b; + S[y] = a; + x = (x + 1) & 0xff; + *out++ = *in ^ S[(a + b) & 0xff]; + + ctx->x = x; + ctx->y = y; +} + +static struct crypto_alg arc4_alg = { + .cra_name = "arc4", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = ARC4_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct arc4_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = ARC4_MIN_KEY_SIZE, + .cia_max_keysize = ARC4_MAX_KEY_SIZE, + .cia_setkey = arc4_set_key, + .cia_encrypt = arc4_crypt, + .cia_decrypt = arc4_crypt } } +}; + +static int __init arc4_init(void) +{ + return crypto_register_alg(&arc4_alg); +} + + +static void __exit arc4_exit(void) +{ + crypto_unregister_alg(&arc4_alg); +} + +module_init(arc4_init); +module_exit(arc4_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ARC4 Cipher Algorithm"); +MODULE_AUTHOR("Jon Oberheide "); diff -urN linux-2.4.25/crypto/cipher.c linux-2.4.26/crypto/cipher.c --- linux-2.4.25/crypto/cipher.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/crypto/cipher.c 2004-04-14 06:05:28.000000000 -0700 @@ -4,7 +4,6 @@ * Cipher operations. * * Copyright (c) 2002 James Morris - * Generic scatterwalk code by Adam J. Richter . * * 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 @@ -17,30 +16,13 @@ #include #include #include -#include -#include #include #include "internal.h" +#include "scatterwalk.h" typedef void (cryptfn_t)(void *, u8 *, const u8 *); typedef void (procfn_t)(struct crypto_tfm *, u8 *, - u8*, cryptfn_t, int enc, void *); - -struct scatter_walk { - struct scatterlist *sg; - struct page *page; - void *data; - unsigned int len_this_page; - unsigned int len_this_segment; - unsigned int offset; -}; - -enum km_type crypto_km_types[] = { - KM_USER0, - KM_USER1, - KM_SOFTIRQ0, - KM_SOFTIRQ1, -}; + u8*, cryptfn_t, int enc, void *, int); static inline void xor_64(u8 *a, const u8 *b) { @@ -57,108 +39,6 @@ } -/* Define sg_next is an inline routine now in case we want to change - scatterlist to a linked list later. */ -static inline struct scatterlist *sg_next(struct scatterlist *sg) -{ - return sg + 1; -} - -void *which_buf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) -{ - if (nbytes <= walk->len_this_page && - (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= - PAGE_CACHE_SIZE) - return walk->data; - else - return scratch; -} - -static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) -{ - if (out) - memcpy(sgdata, buf, nbytes); - else - memcpy(buf, sgdata, nbytes); -} - -static void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) -{ - unsigned int rest_of_page; - - walk->sg = sg; - - walk->page = sg->page; - walk->len_this_segment = sg->length; - - rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); - walk->len_this_page = min(sg->length, rest_of_page); - walk->offset = sg->offset; -} - -static void scatterwalk_map(struct scatter_walk *walk, int out) -{ - walk->data = crypto_kmap(walk->page, out) + walk->offset; -} - -static void scatter_page_done(struct scatter_walk *walk, int out, - unsigned int more) -{ - /* walk->data may be pointing the first byte of the next page; - however, we know we transfered at least one byte. So, - walk->data - 1 will be a virutual address in the mapped page. */ - - if (out) - flush_dcache_page(walk->page); - - if (more) { - walk->len_this_segment -= walk->len_this_page; - - if (walk->len_this_segment) { - walk->page++; - walk->len_this_page = min(walk->len_this_segment, - (unsigned)PAGE_CACHE_SIZE); - walk->offset = 0; - } - else - scatterwalk_start(walk, sg_next(walk->sg)); - } -} - -static void scatter_done(struct scatter_walk *walk, int out, int more) -{ - crypto_kunmap(walk->data, out); - if (walk->len_this_page == 0 || !more) - scatter_page_done(walk, out, more); -} - -/* - * Do not call this unless the total length of all of the fragments - * has been verified as multiple of the block size. - */ -static int copy_chunks(void *buf, struct scatter_walk *walk, - size_t nbytes, int out) -{ - if (buf != walk->data) { - while (nbytes > walk->len_this_page) { - memcpy_dir(buf, walk->data, walk->len_this_page, out); - buf += walk->len_this_page; - nbytes -= walk->len_this_page; - - crypto_kunmap(walk->data, out); - scatter_page_done(walk, out, 1); - scatterwalk_map(walk, out); - } - - memcpy_dir(buf, walk->data, nbytes, out); - } - - walk->offset += nbytes; - walk->len_this_page -= nbytes; - walk->len_this_segment -= nbytes; - return 0; -} - /* * Generic encrypt/decrypt wrapper for ciphers, handles operations across * multiple page boundaries by using temporary blocks. In user context, @@ -191,19 +71,21 @@ scatterwalk_map(&walk_in, 0); scatterwalk_map(&walk_out, 1); - src_p = which_buf(&walk_in, bsize, tmp_src); - dst_p = which_buf(&walk_out, bsize, tmp_dst); + src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); + dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); nbytes -= bsize; - copy_chunks(src_p, &walk_in, bsize, 0); + scatterwalk_copychunks(src_p, &walk_in, bsize, 0); - prfn(tfm, dst_p, src_p, crfn, enc, info); + prfn(tfm, dst_p, src_p, crfn, enc, info, + scatterwalk_samebuf(&walk_in, &walk_out, + src_p, dst_p)); - scatter_done(&walk_in, 0, nbytes); + scatterwalk_done(&walk_in, 0, nbytes); - copy_chunks(dst_p, &walk_out, bsize, 1); - scatter_done(&walk_out, 1, nbytes); + scatterwalk_copychunks(dst_p, &walk_out, bsize, 1); + scatterwalk_done(&walk_out, 1, nbytes); if (!nbytes) return 0; @@ -212,8 +94,8 @@ } } -static void cbc_process(struct crypto_tfm *tfm, - u8 *dst, u8 *src, cryptfn_t fn, int enc, void *info) +static void cbc_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, + cryptfn_t fn, int enc, void *info, int in_place) { u8 *iv = info; @@ -226,10 +108,9 @@ fn(crypto_tfm_ctx(tfm), dst, iv); memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm)); } else { - const int need_stack = (src == dst); - u8 stack[need_stack ? crypto_tfm_alg_blocksize(tfm) : 0]; - u8 *buf = need_stack ? stack : dst; - + u8 stack[in_place ? crypto_tfm_alg_blocksize(tfm) : 0]; + u8 *buf = in_place ? stack : dst; + fn(crypto_tfm_ctx(tfm), buf, src); tfm->crt_u.cipher.cit_xor_block(buf, iv); memcpy(iv, src, crypto_tfm_alg_blocksize(tfm)); @@ -239,7 +120,7 @@ } static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src, - cryptfn_t fn, int enc, void *info) + cryptfn_t fn, int enc, void *info, int in_place) { fn(crypto_tfm_ctx(tfm), dst, src); } diff -urN linux-2.4.25/crypto/internal.h linux-2.4.26/crypto/internal.h --- linux-2.4.25/crypto/internal.h 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.26/crypto/internal.h 2004-04-14 06:05:28.000000000 -0700 @@ -11,6 +11,7 @@ */ #ifndef _CRYPTO_INTERNAL_H #define _CRYPTO_INTERNAL_H +#include #include #include #include diff -urN linux-2.4.25/crypto/scatterwalk.c linux-2.4.26/crypto/scatterwalk.c --- linux-2.4.25/crypto/scatterwalk.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/crypto/scatterwalk.c 2004-04-14 06:05:28.000000000 -0700 @@ -0,0 +1,124 @@ +/* + * Cryptographic API. + * + * Cipher operations. + * + * Copyright (c) 2002 James Morris + * 2002 Adam J. Richter + * 2004 Jean-Luc Cooke + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include "internal.h" +#include "scatterwalk.h" + +enum km_type crypto_km_types[] = { + KM_USER0, + KM_USER1, + KM_SOFTIRQ0, + KM_SOFTIRQ1, +}; + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch) +{ + if (nbytes <= walk->len_this_page && + (((unsigned long)walk->data) & (PAGE_CACHE_SIZE - 1)) + nbytes <= + PAGE_CACHE_SIZE) + return walk->data; + else + return scratch; +} + +static void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) +{ + if (out) + memcpy(sgdata, buf, nbytes); + else + memcpy(buf, sgdata, nbytes); +} + +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg) +{ + unsigned int rest_of_page; + + walk->sg = sg; + + walk->page = sg->page; + walk->len_this_segment = sg->length; + + rest_of_page = PAGE_CACHE_SIZE - (sg->offset & (PAGE_CACHE_SIZE - 1)); + walk->len_this_page = min(sg->length, rest_of_page); + walk->offset = sg->offset; +} + +void scatterwalk_map(struct scatter_walk *walk, int out) +{ + walk->data = crypto_kmap(walk->page, out) + walk->offset; +} + +static void scatterwalk_pagedone(struct scatter_walk *walk, int out, + unsigned int more) +{ + /* walk->data may be pointing the first byte of the next page; + however, we know we transfered at least one byte. So, + walk->data - 1 will be a virutual address in the mapped page. */ + + if (out) + flush_dcache_page(walk->page); + + if (more) { + walk->len_this_segment -= walk->len_this_page; + + if (walk->len_this_segment) { + walk->page++; + walk->len_this_page = min(walk->len_this_segment, + (unsigned)PAGE_CACHE_SIZE); + walk->offset = 0; + } + else + scatterwalk_start(walk, sg_next(walk->sg)); + } +} + +void scatterwalk_done(struct scatter_walk *walk, int out, int more) +{ + crypto_kunmap(walk->data, out); + if (walk->len_this_page == 0 || !more) + scatterwalk_pagedone(walk, out, more); +} + +/* + * Do not call this unless the total length of all of the fragments + * has been verified as multiple of the block size. + */ +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, + size_t nbytes, int out) +{ + if (buf != walk->data) { + while (nbytes > walk->len_this_page) { + memcpy_dir(buf, walk->data, walk->len_this_page, out); + buf += walk->len_this_page; + nbytes -= walk->len_this_page; + + crypto_kunmap(walk->data, out); + scatterwalk_pagedone(walk, out, 1); + scatterwalk_map(walk, out); + } + + memcpy_dir(buf, walk->data, nbytes, out); + } + + walk->offset += nbytes; + walk->len_this_page -= nbytes; + walk->len_this_segment -= nbytes; + return 0; +} diff -urN linux-2.4.25/crypto/scatterwalk.h linux-2.4.26/crypto/scatterwalk.h --- linux-2.4.25/crypto/scatterwalk.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/crypto/scatterwalk.h 2004-04-14 06:05:28.000000000 -0700 @@ -0,0 +1,50 @@ +/* + * Cryptographic API. + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2002 Adam J. Richter + * Copyright (c) 2004 Jean-Luc Cooke + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_SCATTERWALK_H +#define _CRYPTO_SCATTERWALK_H +#include +#include + +struct scatter_walk { + struct scatterlist *sg; + struct page *page; + void *data; + unsigned int len_this_page; + unsigned int len_this_segment; + unsigned int offset; +}; + +/* Define sg_next is an inline routine now in case we want to change + scatterlist to a linked list later. */ +static inline struct scatterlist *sg_next(struct scatterlist *sg) +{ + return sg + 1; +} + +static inline int scatterwalk_samebuf(struct scatter_walk *walk_in, + struct scatter_walk *walk_out, + void *src_p, void *dst_p) +{ + return walk_in->page == walk_out->page && + walk_in->data == src_p && walk_out->data == dst_p; +} + +void *scatterwalk_whichbuf(struct scatter_walk *walk, unsigned int nbytes, void *scratch); +void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg); +int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); +void scatterwalk_map(struct scatter_walk *walk, int out); +void scatterwalk_done(struct scatter_walk *walk, int out, int more); + +#endif /* _CRYPTO_SCATTERWALK_H */ diff -urN linux-2.4.25/crypto/tcrypt.c linux-2.4.26/crypto/tcrypt.c --- linux-2.4.25/crypto/tcrypt.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/crypto/tcrypt.c 2004-04-14 06:05:28.000000000 -0700 @@ -63,7 +63,7 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "deflate", NULL + "arc4", "deflate", NULL }; static void @@ -558,6 +558,10 @@ test_cipher ("cast6", MODE_ECB, ENCRYPT, cast6_enc_tv_template, CAST6_ENC_TEST_VECTORS); test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS); + //ARC4 + test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS); + test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_deflate(); @@ -640,6 +644,11 @@ test_cipher ("cast6", MODE_ECB, DECRYPT, cast6_dec_tv_template, CAST6_DEC_TEST_VECTORS); break; + case 16: + test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS); + test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); + break; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); diff -urN linux-2.4.25/crypto/tcrypt.h linux-2.4.26/crypto/tcrypt.h --- linux-2.4.25/crypto/tcrypt.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/crypto/tcrypt.h 2004-04-14 06:05:28.000000000 -0700 @@ -1488,6 +1488,147 @@ }, }; +/* + * ARC4 test vectors from OpenSSL + */ +#define ARC4_ENC_TEST_VECTORS 7 +#define ARC4_DEC_TEST_VECTORS 7 + +struct cipher_testvec arc4_enc_tv_template[] = +{ + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .ilen = 8, + .result = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }, + .rlen = 8, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 }, + .rlen = 8, + }, { + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ilen = 8, + .result = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a }, + .rlen = 8, + }, { + .key = { 0xef, 0x01, 0x23, 0x45}, + .klen = 4, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .ilen = 20, + .result = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba, + 0x36, 0xb6, 0x78, 0x58 }, + .rlen = 20, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78 }, + .ilen = 28, + .result = { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89, + 0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c, + 0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87, + 0x40, 0x01, 0x1e, 0xcf }, + .rlen = 28, + }, { + .key = { 0xef, 0x01, 0x23, 0x45 }, + .klen = 4, + .input = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }, + .ilen = 10, + .result = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61 }, + .rlen = 10, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + .ilen = 8, + .result = { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 }, + .rlen = 8, + }, +}; + +struct cipher_testvec arc4_dec_tv_template[] = +{ + { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }, + .ilen = 8, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .rlen = 8, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79 }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 8, + .input = { 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a }, + .ilen = 8, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .rlen = 8, + }, { + .key = { 0xef, 0x01, 0x23, 0x45}, + .klen = 4, + .input = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61, 0x5a, 0x11, 0x62, 0xe1, 0xc7, 0xba, + 0x36, 0xb6, 0x78, 0x58 }, + .ilen = 20, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + .rlen = 20, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, + .klen = 8, + .input = { 0x66, 0xa0, 0x94, 0x9f, 0x8a, 0xf7, 0xd6, 0x89, + 0x1f, 0x7f, 0x83, 0x2b, 0xa8, 0x33, 0xc0, 0x0c, + 0x89, 0x2e, 0xbe, 0x30, 0x14, 0x3c, 0xe2, 0x87, + 0x40, 0x01, 0x1e, 0xcf }, + .ilen = 28, + .result = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, + 0x12, 0x34, 0x56, 0x78 }, + .rlen = 28, + }, { + .key = { 0xef, 0x01, 0x23, 0x45 }, + .klen = 4, + .input = { 0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, + 0xbd, 0x61 }, + .ilen = 10, + .result = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }, + .rlen = 10, + }, { + .key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .klen = 16, + .input = { 0x69, 0x72, 0x36, 0x59, 0x1B, 0x52, 0x42, 0xB1 }, + .ilen = 8, + .result = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + .rlen = 8, + }, +}; + + /* * Compression stuff. */ diff -urN linux-2.4.25/drivers/acpi/Config.in linux-2.4.26/drivers/acpi/Config.in --- linux-2.4.25/drivers/acpi/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/Config.in 2004-04-14 06:05:28.000000000 -0700 @@ -25,9 +25,6 @@ tristate ' Fan' CONFIG_ACPI_FAN tristate ' Processor' CONFIG_ACPI_PROCESSOR dep_tristate ' Thermal Zone' CONFIG_ACPI_THERMAL $CONFIG_ACPI_PROCESSOR - if [ "$CONFIG_NUMA" = "y" -a "$CONFIG_X86_64" != "y" ]; then - dep_bool ' NUMA support' CONFIG_ACPI_NUMA $CONFIG_NUMA - fi tristate ' ASUS Laptop Extras' CONFIG_ACPI_ASUS tristate ' Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA bool ' Debug Statements' CONFIG_ACPI_DEBUG diff -urN linux-2.4.25/drivers/acpi/bus.c linux-2.4.26/drivers/acpi/bus.c --- linux-2.4.25/drivers/acpi/bus.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/bus.c 2004-04-14 06:05:28.000000000 -0700 @@ -49,9 +49,7 @@ #define PREFIX "ACPI: " -extern void __init acpi_pic_sci_set_trigger(unsigned int irq); - -extern int acpi_disabled; +extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); FADT_DESCRIPTOR acpi_fadt; struct acpi_device *acpi_root; @@ -1877,11 +1875,23 @@ } #ifdef CONFIG_X86 - /* Ensure the SCI is set to level-triggered, active-low */ - if (acpi_ioapic) - mp_config_ioapic_for_sci(acpi_fadt.sci_int); - else - acpi_pic_sci_set_trigger(acpi_fadt.sci_int); + if (!acpi_ioapic) { + extern acpi_interrupt_flags acpi_sci_flags; + + /* compatible (0) means level (3) */ + if (acpi_sci_flags.trigger == 0) + acpi_sci_flags.trigger = 3; + + /* Set PIC-mode SCI trigger type */ + acpi_pic_sci_set_trigger(acpi_fadt.sci_int, acpi_sci_flags.trigger); + } else { + extern int acpi_sci_override_gsi; + /* + * now that acpi_fadt is initialized, + * update it with result from INT_SRC_OVR parsing + */ + acpi_fadt.sci_int = acpi_sci_override_gsi; + } #endif status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION); @@ -2048,7 +2058,7 @@ result = acpi_bus_init(); if (result) { - acpi_disabled = 1; + disable_acpi(); return_VALUE(result); } @@ -2074,19 +2084,3 @@ return_VOID; } - -int __init -acpi_setup(char *str) -{ - while (str && *str) { - if (strncmp(str, "off", 3) == 0) - acpi_disabled = 1; - str = strchr(str, ','); - if (str) - str += strspn(str, ", \t"); - } - return 1; -} - - -__setup("acpi=", acpi_setup); diff -urN linux-2.4.25/drivers/acpi/dispatcher/dsmethod.c linux-2.4.26/drivers/acpi/dispatcher/dsmethod.c --- linux-2.4.25/drivers/acpi/dispatcher/dsmethod.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dsmethod.c 2004-04-14 06:05:28.000000000 -0700 @@ -106,7 +106,7 @@ /* Create a mutex for the method if there is a concurrency limit */ - if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) && + if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && (!obj_desc->method.semaphore)) { status = acpi_os_create_semaphore (obj_desc->method.concurrency, obj_desc->method.concurrency, @@ -300,34 +300,37 @@ return_ACPI_STATUS (status); } - /* 1) Parse: Create a new walk state for the preempting walk */ + if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { + /* 1) Parse: Create a new walk state for the preempting walk */ - next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, - op, obj_desc, NULL); - if (!next_walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); - } + next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, + op, obj_desc, NULL); + if (!next_walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } - /* Create and init a Root Node */ - op = acpi_ps_create_scope_op (); - if (!op) { - status = AE_NO_MEMORY; - goto cleanup; - } + /* Create and init a Root Node */ - status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, - obj_desc->method.aml_start, obj_desc->method.aml_length, - NULL, NULL, 1); - if (ACPI_FAILURE (status)) { - acpi_ds_delete_walk_state (next_walk_state); - goto cleanup; - } + op = acpi_ps_create_scope_op (); + if (!op) { + status = AE_NO_MEMORY; + goto cleanup; + } + + status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, + obj_desc->method.aml_start, obj_desc->method.aml_length, + NULL, NULL, 1); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (next_walk_state); + goto cleanup; + } - /* Begin AML parse */ + /* Begin AML parse */ - status = acpi_ps_parse_aml (next_walk_state); - acpi_ps_delete_parse_tree (op); + status = acpi_ps_parse_aml (next_walk_state); + acpi_ps_delete_parse_tree (op); + } /* 2) Execute: Create a new state for the preempting walk */ @@ -337,7 +340,6 @@ status = AE_NO_MEMORY; goto cleanup; } - /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always @@ -369,16 +371,25 @@ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Starting nested execution, newstate=%p\n", next_walk_state)); + if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + status = obj_desc->method.implementation (next_walk_state); + return_ACPI_STATUS (status); + } + return_ACPI_STATUS (AE_OK); /* On error, we must delete the new walk state */ cleanup: + if (next_walk_state->method_desc) { + /* Decrement the thread count on the method parse tree */ + + next_walk_state->method_desc->method.thread_count--; + } (void) acpi_ds_terminate_control_method (next_walk_state); acpi_ds_delete_walk_state (next_walk_state); return_ACPI_STATUS (status); - } @@ -500,11 +511,31 @@ } } - /* Decrement the thread count on the method parse tree */ + if (walk_state->method_desc->method.thread_count) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "*** Not deleting method namespace, there are still %d threads\n", + walk_state->method_desc->method.thread_count)); + } - walk_state->method_desc->method.thread_count--; if (!walk_state->method_desc->method.thread_count) { /* + * Support to dynamically change a method from not_serialized to + * Serialized if it appears that the method is written foolishly and + * does not support multiple thread execution. The best example of this + * is if such a method creates namespace objects and blocks. A second + * thread will fail with an AE_ALREADY_EXISTS exception + * + * This code is here because we must wait until the last thread exits + * before creating the synchronization semaphore. + */ + if ((walk_state->method_desc->method.concurrency == 1) && + (!walk_state->method_desc->method.semaphore)) { + status = acpi_os_create_semaphore (1, + 1, + &walk_state->method_desc->method.semaphore); + } + + /* * There are no more threads executing this method. Perform * additional cleanup. * diff -urN linux-2.4.25/drivers/acpi/dispatcher/dsmthdat.c linux-2.4.26/drivers/acpi/dispatcher/dsmthdat.c --- linux-2.4.25/drivers/acpi/dispatcher/dsmthdat.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dsmthdat.c 2004-04-14 06:05:28.000000000 -0700 @@ -206,8 +206,7 @@ * Store the argument in the method/walk descriptor. * Do not copy the arg in order to implement call by reference */ - status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], - walk_state); + status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -465,6 +464,7 @@ return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); default: + ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); } } @@ -597,7 +597,10 @@ /* * If the reference count on the object is more than one, we must - * take a copy of the object before we store. + * take a copy of the object before we store. A reference count + * of exactly 1 means that the object was just created during the + * evaluation of an expression, and we can safely use it since it + * is not used anywhere else. */ new_obj_desc = obj_desc; if (obj_desc->common.reference_count > 1) { diff -urN linux-2.4.25/drivers/acpi/dispatcher/dsobject.c linux-2.4.26/drivers/acpi/dispatcher/dsobject.c --- linux-2.4.25/drivers/acpi/dispatcher/dsobject.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dsobject.c 2004-04-14 06:05:28.000000000 -0700 @@ -582,6 +582,11 @@ obj_desc->reference.opcode = AML_ARG_OP; obj_desc->reference.offset = opcode - AML_ARG_OP; + +#ifndef ACPI_NO_METHOD_EXECUTION + status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset, + walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); +#endif break; default: /* Other literals, etc.. */ diff -urN linux-2.4.25/drivers/acpi/dispatcher/dsopcode.c linux-2.4.26/drivers/acpi/dispatcher/dsopcode.c --- linux-2.4.25/drivers/acpi/dispatcher/dsopcode.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dsopcode.c 2004-04-14 06:05:28.000000000 -0700 @@ -243,8 +243,8 @@ node = obj_desc->buffer.node; if (!node) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "No pointer back to NS node in buffer %p\n", obj_desc)); + ACPI_REPORT_ERROR (( + "No pointer back to NS node in buffer obj %p\n", obj_desc)); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -290,7 +290,7 @@ node = obj_desc->package.node; if (!node) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_REPORT_ERROR (( "No pointer back to NS node in package %p\n", obj_desc)); return_ACPI_STATUS (AE_AML_INTERNAL); } diff -urN linux-2.4.25/drivers/acpi/dispatcher/dsutils.c linux-2.4.26/drivers/acpi/dispatcher/dsutils.c --- linux-2.4.25/drivers/acpi/dispatcher/dsutils.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dsutils.c 2004-04-14 06:05:28.000000000 -0700 @@ -280,7 +280,8 @@ /* * Attempt to resolve each of the valid operands - * Method arguments are passed by value, not by reference + * Method arguments are passed by reference, not by value. This means + * that the actual objects are passed, not copies of the objects. */ for (i = 0; i < walk_state->num_operands; i++) { status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); diff -urN linux-2.4.25/drivers/acpi/dispatcher/dswstate.c linux-2.4.26/drivers/acpi/dispatcher/dswstate.c --- linux-2.4.25/drivers/acpi/dispatcher/dswstate.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/dispatcher/dswstate.c 2004-04-14 06:05:28.000000000 -0700 @@ -328,7 +328,7 @@ state = walk_state->results; if (!state) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result stack frame\n")); + ACPI_REPORT_ERROR (("No result stack frame during push\n")); return (AE_AML_INTERNAL); } diff -urN linux-2.4.25/drivers/acpi/ec.c linux-2.4.26/drivers/acpi/ec.c --- linux-2.4.25/drivers/acpi/ec.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/ec.c 2004-04-14 06:05:28.000000000 -0700 @@ -715,7 +715,7 @@ * Install GPE handler */ status = acpi_install_gpe_handler(NULL, ec->gpe_bit, - ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); + ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } @@ -799,7 +799,7 @@ * Install GPE handler */ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, - ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, + ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec_ecdt); if (ACPI_FAILURE(status)) { goto error; diff -urN linux-2.4.25/drivers/acpi/events/evgpe.c linux-2.4.26/drivers/acpi/events/evgpe.c --- linux-2.4.25/drivers/acpi/events/evgpe.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/events/evgpe.c 2004-04-14 06:05:28.000000000 -0700 @@ -99,9 +99,8 @@ return (NULL); } - /* - * A Non-null gpe_device means this is a GPE Block Device. - */ + /* A Non-NULL gpe_device means this is a GPE Block Device */ + obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) gpe_device); if (!obj_desc || !obj_desc->device.gpe_block) { @@ -149,6 +148,11 @@ ACPI_FUNCTION_NAME ("ev_gpe_detect"); + /* Check for the case where there are no GPEs */ + + if (!gpe_xrupt_list) { + return (int_status); + } /* Examine all GPE blocks attached to this interrupt level */ @@ -292,7 +296,7 @@ } } - if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) { + if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after handling * the event. @@ -341,7 +345,7 @@ * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if (gpe_event_info->flags & ACPI_EVENT_EDGE_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n", @@ -364,7 +368,7 @@ /* It is now safe to clear level-triggered events. */ - if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) { + if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( diff -urN linux-2.4.25/drivers/acpi/events/evgpeblk.c linux-2.4.26/drivers/acpi/events/evgpeblk.c --- linux-2.4.25/drivers/acpi/events/evgpeblk.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/events/evgpeblk.c 2004-04-14 06:05:28.000000000 -0700 @@ -168,11 +168,11 @@ * information for quick lookup during GPE dispatch * * The name of each GPE control method is of the form: - * "_Lnn" or "_Enn" - * Where: - * L - means that the GPE is level triggered - * E - means that the GPE is edge triggered - * nn - is the GPE number [in HEX] + * "_Lxx" or "_Exx" + * Where: + * L - means that the GPE is level triggered + * E - means that the GPE is edge triggered + * xx - is the GPE number [in HEX] * ******************************************************************************/ @@ -188,36 +188,41 @@ u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; - acpi_status status; ACPI_FUNCTION_TRACE ("ev_save_method_info"); - /* Extract the name from the object and convert to a string */ - + /* + * _Lxx and _Exx GPE method support + * + * 1) Extract the name from the object and convert to a string + */ ACPI_MOVE_32_TO_32 (name, &((struct acpi_namespace_node *) obj_handle)->name.integer); name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd character - * of the method name + * 2) Edge/Level determination is based on the 2nd character + * of the method name + * + * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE if a + * _PRW object is found that points to this GPE. */ switch (name[1]) { case 'L': - type = ACPI_EVENT_LEVEL_TRIGGERED; + type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; break; case 'E': - type = ACPI_EVENT_EDGE_TRIGGERED; + type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME; break; default: /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n", + "Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n", name)); return_ACPI_STATUS (AE_OK); } @@ -229,7 +234,7 @@ /* Conversion failed; invalid method, just ignore it */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n", + "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n", name)); return_ACPI_STATUS (AE_OK); } @@ -255,13 +260,6 @@ gpe_event_info->flags = type; gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; - /* Enable the GPE (SCIs should be disabled at this point) */ - - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); @@ -271,6 +269,122 @@ /******************************************************************************* * + * FUNCTION: acpi_ev_get_gpe_type + * + * PARAMETERS: Callback from walk_namespace + * + * RETURN: Status + * + * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a + * Device. Run the _PRW method. If present, extract the GPE + * number and mark the GPE as a WAKE GPE. + * + ******************************************************************************/ + +static acpi_status +acpi_ev_get_gpe_type ( + acpi_handle obj_handle, + u32 level, + void *info, + void **return_value) +{ + struct acpi_gpe_walk_info *gpe_info = (void *) info; + struct acpi_namespace_node *gpe_device; + struct acpi_gpe_block_info *gpe_block; + struct acpi_namespace_node *target_gpe_device; + struct acpi_gpe_event_info *gpe_event_info; + union acpi_operand_object *pkg_desc; + union acpi_operand_object *obj_desc; + u32 gpe_number; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_get_gpe_type"); + + + /* Check for a _PRW method under this device */ + + status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW, + ACPI_BTYPE_PACKAGE, &pkg_desc); + if (status == AE_NOT_FOUND) { + return_ACPI_STATUS (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* The returned _PRW package must have at least two elements */ + + if (pkg_desc->package.count < 2) { + goto cleanup; + } + + /* Extract pointers from the input context */ + + gpe_device = gpe_info->gpe_device; + gpe_block = gpe_info->gpe_block; + + /* + * The _PRW object must return a package, we are only interested + * in the first element + */ + obj_desc = pkg_desc->package.elements[0]; + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { + /* Use FADT-defined GPE device (from definition of _PRW) */ + + target_gpe_device = acpi_gbl_fadt_gpe_device; + + /* Integer is the GPE number in the FADT described GPE blocks */ + + gpe_number = (u32) obj_desc->integer.value; + } + else if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) { + /* Package contains a GPE reference and GPE number within a GPE block */ + + if ((obj_desc->package.count < 2) || + (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) || + (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) { + goto cleanup; + } + + /* Get GPE block reference and decode */ + + target_gpe_device = obj_desc->package.elements[0]->reference.node; + gpe_number = (u32) obj_desc->package.elements[1]->integer.value; + } + else { + /* Unknown type, just ignore it */ + + goto cleanup; + } + + /* + * Is this GPE within this block? + * + * TRUE iff these conditions are true: + * 1) The GPE devices match. + * 2) The GPE index(number) is within the range of the Gpe Block + * associated with the GPE device. + */ + if ((gpe_device == target_gpe_device) && + (gpe_number >= gpe_block->block_base_number) && + (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { + /* Mark GPE for WAKE but DISABLED (even for wake) */ + + gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; + gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE; + } + +cleanup: + acpi_ut_remove_reference (pkg_desc); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ev_get_gpe_xrupt_block * * PARAMETERS: interrupt_level - Interrupt for a GPE block @@ -695,8 +809,13 @@ struct acpi_gpe_block_info **return_gpe_block) { struct acpi_gpe_block_info *gpe_block; + struct acpi_gpe_event_info *gpe_event_info; + acpi_native_uint i; + acpi_native_uint j; + u32 wake_gpe_count; + u32 gpe_enabled_count; acpi_status status; - + struct acpi_gpe_walk_info gpe_info; ACPI_FUNCTION_TRACE ("ev_create_gpe_block"); @@ -737,7 +856,8 @@ /* Dump info about this GPE block */ - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n", gpe_block->block_base_number, (u32) (gpe_block->block_base_number + ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)), @@ -752,6 +872,58 @@ ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info, gpe_block, NULL); + /* + * Runtime option: Should Wake GPEs be enabled at runtime? The default is + * No,they should only be enabled just as the machine goes to sleep. + */ + if (acpi_gbl_leave_wake_gpes_disabled) { + /* + * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each + * GPE that has one or more _PRWs that reference it is by definition a + * WAKE GPE and will not be enabled while the machine is running.) + */ + gpe_info.gpe_block = gpe_block; + gpe_info.gpe_device = gpe_device; + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type, + &gpe_info, NULL); + } + + /* + * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have + * a corresponding _Lxx or _Exx method. All other GPEs must be enabled via + * the acpi_enable_gpe() external interface. + */ + wake_gpe_count = 0; + gpe_enabled_count = 0; + + for (i = 0; i < gpe_block->register_count; i++) { + for (j = 0; j < 8; j++) { + /* Get the info block for this particular GPE */ + + gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; + if ((gpe_event_info->method_node) && + ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) { + /* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */ + + status = acpi_hw_enable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + gpe_enabled_count++; + } + + if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) { + wake_gpe_count++; + } + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Found %u Wake, Enabled %u Runtime GPEs in this block\n", + wake_gpe_count, gpe_enabled_count)); + /* Return the new block */ if (return_gpe_block) { @@ -775,27 +947,25 @@ ******************************************************************************/ acpi_status -acpi_ev_gpe_initialize (void) +acpi_ev_gpe_initialize ( + void) { u32 register_count0 = 0; u32 register_count1 = 0; u32 gpe_number_max = 0; - acpi_handle gpe_device; acpi_status status; ACPI_FUNCTION_TRACE ("ev_gpe_initialize"); - /* Get a handle to the predefined _GPE object */ - - status = acpi_get_handle (NULL, "\\_GPE", &gpe_device); + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* - * Initialize the GPE Blocks defined in the FADT + * Initialize the GPE Block(s) defined in the FADT * * Why the GPE register block lengths are divided by 2: From the ACPI Spec, * section "General-Purpose Event Registers", we have: @@ -829,8 +999,9 @@ /* Install GPE Block 0 */ - status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe0_blk, + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk, register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); + if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "Could not create GPE Block 0, %s\n", @@ -861,9 +1032,10 @@ else { /* Install GPE Block 1 */ - status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe1_blk, + status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk, register_count1, acpi_gbl_FADT->gpe1_base, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]); + if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "Could not create GPE Block 1, %s\n", @@ -885,7 +1057,8 @@ /* GPEs are not required by ACPI, this is OK */ ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n")); - return_ACPI_STATUS (AE_OK); + status = AE_OK; + goto cleanup; } /* Check for Max GPE number out-of-range */ @@ -893,9 +1066,12 @@ if (gpe_number_max > ACPI_GPE_MAX) { ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n", gpe_number_max)); - return_ACPI_STATUS (AE_BAD_VALUE); + status = AE_BAD_VALUE; + goto cleanup; } +cleanup: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_OK); } diff -urN linux-2.4.25/drivers/acpi/events/evmisc.c linux-2.4.26/drivers/acpi/events/evmisc.c --- linux-2.4.25/drivers/acpi/events/evmisc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/events/evmisc.c 2004-04-14 06:05:28.000000000 -0700 @@ -97,6 +97,20 @@ * ******************************************************************************/ +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_notify_value_names[] = +{ + "Bus Check", + "Device Check", + "Device Wake", + "Eject request", + "Device Check Light", + "Frequency Mismatch", + "Bus Mode Mismatch", + "Power Fault" +}; +#endif + acpi_status acpi_ev_queue_notify_request ( struct acpi_namespace_node *node, @@ -112,7 +126,7 @@ /* - * For value 1 (Ejection Request), some device method may need to be run. + * For value 3 (Ejection Request), some device method may need to be run. * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run. * For value 0x80 (Status Change) on the power button or sleep button, * initiate soft-off or sleep operation? @@ -120,26 +134,13 @@ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dispatching Notify(%X) on node %p\n", notify_value, node)); - switch (notify_value) { - case 0: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Re-enumerate Devices\n")); - break; - - case 1: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Ejection Request\n")); - break; - - case 2: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Device Wake\n")); - break; - - case 0x80: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Status Change\n")); - break; - - default: - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unknown Notify Value: %X \n", notify_value)); - break; + if (notify_value <= 7) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: %s\n", + acpi_notify_value_names[notify_value])); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "notify value: 0x2.2_x **Device Specific**\n", + notify_value)); } /* diff -urN linux-2.4.25/drivers/acpi/events/evxfevnt.c linux-2.4.26/drivers/acpi/events/evxfevnt.c --- linux-2.4.25/drivers/acpi/events/evxfevnt.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/events/evxfevnt.c 2004-04-14 06:05:28.000000000 -0700 @@ -247,16 +247,29 @@ goto unlock_and_exit; } - /* Enable the requested GPE number */ - - status = acpi_hw_enable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } + /* Check for Wake vs Runtime GPE */ if (flags & ACPI_EVENT_WAKE_ENABLE) { + /* Ensure the requested wake GPE is disabled */ + + status = acpi_hw_disable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + + /* Defer Enable of Wake GPE until sleep time */ + acpi_hw_enable_gpe_for_wakeup (gpe_event_info); } + else { + /* Enable the requested runtime GPE */ + + status = acpi_hw_enable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } + unlock_and_exit: if (flags & ACPI_NOT_ISR) { diff -urN linux-2.4.25/drivers/acpi/executer/exconvrt.c linux-2.4.26/drivers/acpi/executer/exconvrt.c --- linux-2.4.25/drivers/acpi/executer/exconvrt.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exconvrt.c 2004-04-14 06:05:28.000000000 -0700 @@ -55,8 +55,9 @@ * * FUNCTION: acpi_ex_convert_to_integer * - * PARAMETERS: *obj_desc - Object to be converted. Must be an + * PARAMETERS: obj_desc - Object to be converted. Must be an * Integer, Buffer, or String + * result_desc - Where the new Integer object is returned * walk_state - Current method state * * RETURN: Status @@ -189,8 +190,9 @@ * * FUNCTION: acpi_ex_convert_to_buffer * - * PARAMETERS: *obj_desc - Object to be converted. Must be an + * PARAMETERS: obj_desc - Object to be converted. Must be an * Integer, Buffer, or String + * result_desc - Where the new buffer object is returned * walk_state - Current method state * * RETURN: Status @@ -319,6 +321,7 @@ ACPI_FUNCTION_ENTRY (); + if (data_width < sizeof (acpi_integer)) { leading_zero = FALSE; length = data_width; @@ -328,22 +331,21 @@ length = sizeof (acpi_integer); } - switch (base) { case 10: remainder = 0; - for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0 ; i--) { + for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0; i--) { /* Divide by nth factor of 10 */ digit = integer; - for (j = 1; j < i; j++) { + for (j = 0; j < i; j++) { (void) acpi_ut_short_divide (&digit, 10, &digit, &remainder); } /* Create the decimal digit */ - if (digit != 0) { + if (remainder != 0) { leading_zero = FALSE; } @@ -354,6 +356,7 @@ } break; + case 16: /* Copy the integer to the buffer */ @@ -372,13 +375,14 @@ } break; + default: break; } /* * Since leading zeros are supressed, we must check for the case where - * the integer equals 0. + * the integer equals 0 * * Finally, null terminate the string and return the length */ @@ -396,8 +400,11 @@ * * FUNCTION: acpi_ex_convert_to_string * - * PARAMETERS: *obj_desc - Object to be converted. Must be an - * Integer, Buffer, or String + * PARAMETERS: obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * result_desc - Where the string object is returned + * Base - 10 or 16 + * max_length - Max length of the returned string * walk_state - Current method state * * RETURN: Status @@ -415,10 +422,10 @@ struct acpi_walk_state *walk_state) { union acpi_operand_object *ret_desc; - u32 i; - u32 string_length; u8 *new_buf; u8 *pointer; + u32 string_length; + u32 i; ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc); @@ -539,7 +546,6 @@ return_ACPI_STATUS (AE_TYPE); } - /* * If we are about to overwrite the original object on the operand stack, * we must remove a reference on the original object because we are @@ -562,6 +568,7 @@ * * PARAMETERS: destination_type - Current type of the destination * source_desc - Source object to be converted. + * result_desc - Where the converted object is returned * walk_state - Current method state * * RETURN: Status @@ -653,6 +660,8 @@ default: + ACPI_REPORT_ERROR (("Bad destination type during conversion: %X\n", + destination_type)); status = AE_AML_INTERNAL; break; } @@ -672,6 +681,8 @@ GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args), walk_state->op_info->name, acpi_ut_get_type_name (destination_type))); + ACPI_REPORT_ERROR (("Bad Target Type (ARGI): %X\n", + GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args))) status = AE_AML_INTERNAL; } diff -urN linux-2.4.25/drivers/acpi/executer/excreate.c linux-2.4.26/drivers/acpi/executer/excreate.c --- linux-2.4.25/drivers/acpi/executer/excreate.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/excreate.c 2004-04-14 06:05:28.000000000 -0700 @@ -84,14 +84,15 @@ alias_node = (struct acpi_namespace_node *) walk_state->operands[0]; target_node = (struct acpi_namespace_node *) walk_state->operands[1]; - if (target_node->type == ACPI_TYPE_LOCAL_ALIAS) { + if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || + (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { /* * Dereference an existing alias so that we don't create a chain * of aliases. With this code, we guarantee that an alias is * always exactly one level of indirection away from the * actual aliased name. */ - target_node = (struct acpi_namespace_node *) target_node->object; + target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object); } /* @@ -117,6 +118,17 @@ alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); break; + case ACPI_TYPE_METHOD: + + /* + * The new alias has the type ALIAS and points to the original + * NS node, not the object itself. This is because for these + * types, the object can change dynamically via a Store. + */ + alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; + alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); + break; + default: /* Attach the original source object to the new Alias Node */ @@ -587,27 +599,33 @@ obj_desc->method.aml_start = aml_start; obj_desc->method.aml_length = aml_length; - /* disassemble the method flags */ - + /* + * Disassemble the method flags. Split off the Arg Count + * for efficiency + */ method_flags = (u8) operand[1]->integer.value; - obj_desc->method.method_flags = method_flags; - obj_desc->method.param_count = (u8) (method_flags & METHOD_FLAGS_ARG_COUNT); + obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT); + obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); /* * Get the concurrency count. If required, a semaphore will be * created for this method when it is parsed. */ - if (method_flags & METHOD_FLAGS_SERIALIZED) { + if (acpi_gbl_all_methods_serialized) { + obj_desc->method.concurrency = 1; + obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; + } + else if (method_flags & AML_METHOD_SERIALIZED) { /* * ACPI 1.0: Concurrency = 1 * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1) */ obj_desc->method.concurrency = (u8) - (((method_flags & METHOD_FLAGS_SYNCH_LEVEL) >> 4) + 1); + (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1); } else { - obj_desc->method.concurrency = INFINITE_CONCURRENCY; + obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY; } /* Attach the new object to the method Node */ diff -urN linux-2.4.25/drivers/acpi/executer/exdump.c linux-2.4.26/drivers/acpi/executer/exdump.c --- linux-2.4.25/drivers/acpi/executer/exdump.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exdump.c 2004-04-14 06:05:28.000000000 -0700 @@ -774,6 +774,7 @@ case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: case ACPI_TYPE_LOCAL_EXTRA: case ACPI_TYPE_LOCAL_DATA: default: diff -urN linux-2.4.25/drivers/acpi/executer/exfldio.c linux-2.4.26/drivers/acpi/executer/exfldio.c --- linux-2.4.25/drivers/acpi/executer/exfldio.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exfldio.c 2004-04-14 06:05:28.000000000 -0700 @@ -154,8 +154,7 @@ field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); - #ifdef CONFIG_ACPI_RELAXED_AML - { + if (!acpi_strict) { /* * Allow access to the field if it is within the region size * rounded up to a multiple of the access byte width. This @@ -186,9 +185,9 @@ return_ACPI_STATUS (AE_OK); } } - #else + else { return_ACPI_STATUS (AE_AML_REGION_LIMIT); - #endif + } } return_ACPI_STATUS (AE_OK); @@ -507,8 +506,8 @@ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n", - obj_desc, acpi_ut_get_object_type_name (obj_desc))); + ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", + ACPI_GET_OBJECT_TYPE (obj_desc))); status = AE_AML_INTERNAL; break; } diff -urN linux-2.4.25/drivers/acpi/executer/exmisc.c linux-2.4.26/drivers/acpi/executer/exmisc.c --- linux-2.4.25/drivers/acpi/executer/exmisc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exmisc.c 2004-04-14 06:05:28.000000000 -0700 @@ -103,7 +103,7 @@ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference subtype %X\n", + ACPI_REPORT_ERROR (("Unknown Reference subtype in get ref %X\n", obj_desc->reference.opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -121,8 +121,8 @@ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p has invalid descriptor [%s]\n", - obj_desc, acpi_ut_get_descriptor_name (obj_desc))); + ACPI_REPORT_ERROR (("Invalid descriptor type in get ref: %X\n", + ACPI_GET_DESCRIPTOR_TYPE (obj_desc))); return_ACPI_STATUS (AE_TYPE); } @@ -349,6 +349,8 @@ /* Invalid object type, should not happen here */ + ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n", + ACPI_GET_OBJECT_TYPE (obj_desc1))); status = AE_AML_INTERNAL; return_desc = NULL; } diff -urN linux-2.4.25/drivers/acpi/executer/exmutex.c linux-2.4.26/drivers/acpi/executer/exmutex.c --- linux-2.4.25/drivers/acpi/executer/exmutex.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exmutex.c 2004-04-14 06:05:28.000000000 -0700 @@ -176,15 +176,18 @@ /* * Support for multiple acquires by the owning thread */ + if (obj_desc->mutex.owner_thread) { + /* Special case for Global Lock, allow all threads */ - if ((obj_desc->mutex.owner_thread) && - (obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id)) { - /* - * The mutex is already owned by this thread, - * just increment the acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS (AE_OK); + if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) || + (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) { + /* + * The mutex is already owned by this thread, + * just increment the acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS (AE_OK); + } } /* Acquire the mutex, wait if necessary */ @@ -254,9 +257,12 @@ return_ACPI_STATUS (AE_AML_INTERNAL); } - /* The Mutex is owned, but this thread must be the owner */ - - if (obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) { + /* + * The Mutex is owned, but this thread must be the owner. + * Special case for Global Lock, any thread can release + */ + if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) && + (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) { ACPI_REPORT_ERROR (( "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n", walk_state->thread->thread_id, diff -urN linux-2.4.25/drivers/acpi/executer/exoparg2.c linux-2.4.26/drivers/acpi/executer/exoparg2.c --- linux-2.4.25/drivers/acpi/executer/exoparg2.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exoparg2.c 2004-04-14 06:05:28.000000000 -0700 @@ -329,6 +329,8 @@ break; default: + ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n", + ACPI_GET_OBJECT_TYPE (operand[0]))); status = AE_AML_INTERNAL; } @@ -433,7 +435,7 @@ } return_desc->reference.target_type = ACPI_TYPE_PACKAGE; - return_desc->reference.object = operand[0]->package.elements [index]; + return_desc->reference.object = operand[0]; return_desc->reference.where = &operand[0]->package.elements [index]; } else { diff -urN linux-2.4.25/drivers/acpi/executer/exprep.c linux-2.4.26/drivers/acpi/executer/exprep.c --- linux-2.4.25/drivers/acpi/executer/exprep.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exprep.c 2004-04-14 06:05:28.000000000 -0700 @@ -507,7 +507,7 @@ (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width)); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Index Object\n")); + ACPI_REPORT_ERROR (("Null Index Object during field prep\n")); return_ACPI_STATUS (AE_AML_INTERNAL); } diff -urN linux-2.4.25/drivers/acpi/executer/exresnte.c linux-2.4.26/drivers/acpi/executer/exresnte.c --- linux-2.4.25/drivers/acpi/executer/exresnte.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exresnte.c 2004-04-14 06:05:28.000000000 -0700 @@ -108,10 +108,11 @@ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n", node, source_desc, acpi_ut_get_type_name (entry_type))); - if (entry_type == ACPI_TYPE_LOCAL_ALIAS) { + if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) || + (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { /* There is always exactly one level of indirection */ - node = (struct acpi_namespace_node *) node->object; + node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); source_desc = acpi_ns_get_attached_object (node); entry_type = acpi_ns_get_type ((acpi_handle) node); *object_ptr = node; diff -urN linux-2.4.25/drivers/acpi/executer/exresolv.c linux-2.4.26/drivers/acpi/executer/exresolv.c --- linux-2.4.25/drivers/acpi/executer/exresolv.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exresolv.c 2004-04-14 06:05:28.000000000 -0700 @@ -238,8 +238,8 @@ /* Invalid reference object */ - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Unknown target_type %X in Index/Reference obj %p\n", + ACPI_REPORT_ERROR (( + "During resolve, Unknown target_type %X in Index/Reference obj %p\n", stack_desc->reference.target_type, stack_desc)); status = AE_AML_INTERNAL; break; @@ -258,7 +258,7 @@ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X (%s) in %p\n", + ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n", opcode, acpi_ps_get_opcode_name (opcode), stack_desc)); status = AE_AML_INTERNAL; break; diff -urN linux-2.4.25/drivers/acpi/executer/exresop.c linux-2.4.26/drivers/acpi/executer/exresop.c --- linux-2.4.25/drivers/acpi/executer/exresop.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exresop.c 2004-04-14 06:05:28.000000000 -0700 @@ -154,7 +154,7 @@ arg_types = op_info->runtime_args; if (arg_types == ARGI_INVALID_OPCODE) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - %X is not a valid AML opcode\n", + ACPI_REPORT_ERROR (("resolve_operands: %X is not a valid AML opcode\n", opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); @@ -172,7 +172,7 @@ */ while (GET_CURRENT_ARG_TYPE (arg_types)) { if (!stack_ptr || !*stack_ptr) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null stack entry at %p\n", + ACPI_REPORT_ERROR (("resolve_operands: Null stack entry at %p\n", stack_ptr)); return_ACPI_STATUS (AE_AML_INTERNAL); diff -urN linux-2.4.25/drivers/acpi/executer/exstore.c linux-2.4.26/drivers/acpi/executer/exstore.c --- linux-2.4.25/drivers/acpi/executer/exstore.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exstore.c 2004-04-14 06:05:28.000000000 -0700 @@ -125,7 +125,7 @@ default: - /* Destination is not an Reference */ + /* Destination is not a Reference object */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Destination is not a Reference or Constant object [%p]\n", dest_desc)); @@ -189,35 +189,38 @@ switch (ACPI_GET_OBJECT_TYPE (source_desc)) { case ACPI_TYPE_INTEGER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n", + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64 (source_desc->integer.value))); break; case ACPI_TYPE_BUFFER: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length %.2X\n", + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X", (u32) source_desc->buffer.length)); + ACPI_DUMP_BUFFER (source_desc->buffer.pointer, + (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); break; case ACPI_TYPE_STRING: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s\n", source_desc->string.pointer)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Length 0x%.2X, \"%s\"\n", + source_desc->string.length, source_desc->string.pointer)); break; case ACPI_TYPE_PACKAGE: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Elements Ptr - %p\n", - source_desc->package.elements)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Size 0x%.2X Elements Ptr - %p\n", + source_desc->package.count, source_desc->package.elements)); break; default: - ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "Type %s %p\n", - acpi_ut_get_object_type_name (source_desc), source_desc)); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n", + source_desc)); break; } @@ -227,7 +230,7 @@ default: - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Reference opcode %X\n", + ACPI_REPORT_ERROR (("ex_store: Unknown Reference opcode %X\n", ref_desc->reference.opcode)); ACPI_DUMP_ENTRY (ref_desc, ACPI_LV_ERROR); @@ -263,6 +266,7 @@ union acpi_operand_object *obj_desc; union acpi_operand_object *new_desc; u8 value = 0; + u32 i; ACPI_FUNCTION_TRACE ("ex_store_object_to_index"); @@ -283,6 +287,7 @@ /* * The object at *(index_desc->Reference.Where) is the * element within the package that is to be modified. + * The parent package object is at index_desc->Reference.Object */ obj_desc = *(index_desc->reference.where); @@ -309,6 +314,12 @@ if (new_desc == source_desc) { acpi_ut_add_reference (new_desc); } + + /* Increment reference count by the ref count of the parent package -1 */ + + for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + acpi_ut_add_reference (new_desc); + } } break; diff -urN linux-2.4.25/drivers/acpi/executer/exstoren.c linux-2.4.26/drivers/acpi/executer/exstoren.c --- linux-2.4.25/drivers/acpi/executer/exstoren.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/executer/exstoren.c 2004-04-14 06:05:28.000000000 -0700 @@ -112,6 +112,12 @@ } } + /* For copy_object, no further validation necessary */ + + if (walk_state->opcode == AML_COPY_OP) { + break; + } + /* * Must have a Integer, Buffer, or String */ @@ -132,11 +138,12 @@ case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: /* * Aliases are resolved by acpi_ex_prep_operands */ - ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into Alias - should never happen\n")); + ACPI_REPORT_ERROR (("Store into Alias - should never happen\n")); status = AE_AML_INTERNAL; break; diff -urN linux-2.4.25/drivers/acpi/hardware/hwgpe.c linux-2.4.26/drivers/acpi/hardware/hwgpe.c --- linux-2.4.25/drivers/acpi/hardware/hwgpe.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/hardware/hwgpe.c 2004-04-14 06:05:28.000000000 -0700 @@ -53,9 +53,9 @@ * * FUNCTION: acpi_hw_enable_gpe * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Enable a single GPE. * @@ -95,7 +95,7 @@ * * FUNCTION: acpi_hw_enable_gpe_for_wakeup * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled * * RETURN: None * @@ -122,9 +122,11 @@ } /* - * Set the bit so we will not disable this when sleeping + * Set the bit so we will not enable this GPE when sleeping (and disable + * it upon wake) */ gpe_register_info->wake_enable |= gpe_event_info->bit_mask; + gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED); } @@ -132,9 +134,9 @@ * * FUNCTION: acpi_hw_disable_gpe * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Disable a single GPE. * @@ -177,6 +179,8 @@ return (status); } + /* Make sure this GPE is disabled for wake, also */ + acpi_hw_disable_gpe_for_wakeup (gpe_event_info); return (AE_OK); } @@ -186,7 +190,7 @@ * * FUNCTION: acpi_hw_disable_gpe_for_wakeup * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to be disabled * * RETURN: None * @@ -212,9 +216,8 @@ return; } - /* - * Clear the bit so we will disable this when sleeping - */ + /* Clear the bit so we will disable this when sleeping */ + gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask); } @@ -223,11 +226,11 @@ * * FUNCTION: acpi_hw_clear_gpe * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared * - * RETURN: None + * RETURN: status_status * - * DESCRIPTION: Clear a single GPE. + * DESCRIPTION: Clear the status bit for a single GPE. * ******************************************************************************/ @@ -256,9 +259,10 @@ * * FUNCTION: acpi_hw_get_gpe_status * - * PARAMETERS: gpe_number - The GPE + * PARAMETERS: gpe_event_info - Info block for the GPE to queried + * event_status - Where the GPE status is returned * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Return the status of a single GPE. * @@ -376,7 +380,7 @@ * * RETURN: Status * - * DESCRIPTION: Clear all GPEs within a GPE block + * DESCRIPTION: Clear status bits for all GPEs within a GPE block * ******************************************************************************/ @@ -392,7 +396,7 @@ /* Examine each GPE Register within the block */ for (i = 0; i < gpe_block->register_count; i++) { - /* Clear all GPEs in this register */ + /* Clear status on all GPEs in this register */ status = acpi_hw_low_level_write (8, 0xFF, &gpe_block->register_info[i].status_address); @@ -407,19 +411,20 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_disable_non_wakeup_gpe_block + * FUNCTION: acpi_hw_prepare_gpe_block_for_sleep * * PARAMETERS: gpe_xrupt_info - GPE Interrupt info * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Disable all GPEs except wakeup GPEs in a GPE block + * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within + * a single GPE block * ******************************************************************************/ static acpi_status -acpi_hw_disable_non_wakeup_gpe_block ( +acpi_hw_prepare_gpe_block_for_sleep ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) { @@ -437,8 +442,11 @@ for (i = 0; i < gpe_block->register_count; i++) { /* - * Read the enabled status of all GPEs. We + * Read the enabled/disabled status of all GPEs. We * will be using it to restore all the GPEs later. + * + * NOTE: Wake GPEs are are ALL disabled at this time, so when we wake + * and restore this register, they will be automatically disabled. */ status = acpi_hw_low_level_read (8, &in_value, &gpe_register_info->enable_address); @@ -449,7 +457,8 @@ gpe_register_info->enable = (u8) in_value; /* - * Disable all GPEs except wakeup GPEs. + * 1) Disable all runtime GPEs + * 2) Enable all wakeup GPEs */ status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, &gpe_register_info->enable_address); @@ -457,6 +466,8 @@ return (status); } + /* Point to next GPE register */ + gpe_register_info++; } @@ -466,22 +477,22 @@ /****************************************************************************** * - * FUNCTION: acpi_hw_disable_non_wakeup_gpes + * FUNCTION: acpi_hw_prepare_gpes_for_sleep * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * - * DESCRIPTION: Disable all non-wakeup GPEs + * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs. * Called with interrupts disabled. The interrupt handler also * modifies gpe_register_info->Enable, so it should not be - * given the chance to run until after non-wake GPEs are + * given the chance to run until after the runtime GPEs are * re-enabled. * ******************************************************************************/ acpi_status -acpi_hw_disable_non_wakeup_gpes ( +acpi_hw_prepare_gpes_for_sleep ( void) { acpi_status status; @@ -490,27 +501,27 @@ ACPI_FUNCTION_ENTRY (); - status = acpi_ev_walk_gpe_list (acpi_hw_disable_non_wakeup_gpe_block); - + status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep); return (status); } /****************************************************************************** * - * FUNCTION: acpi_hw_enable_non_wakeup_gpe_block + * FUNCTION: acpi_hw_restore_gpe_block_on_wake * * PARAMETERS: gpe_xrupt_info - GPE Interrupt info * gpe_block - Gpe Block info * * RETURN: Status * - * DESCRIPTION: Enable a single GPE. + * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one + * GPE block * ******************************************************************************/ static acpi_status -acpi_hw_enable_non_wakeup_gpe_block ( +acpi_hw_restore_gpe_block_on_wake ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block) { @@ -528,9 +539,21 @@ /* Examine each GPE register within the block */ for (i = 0; i < gpe_block->register_count; i++) { + /* Clear the entire status register */ + + status = acpi_hw_low_level_write (8, 0xFF, + &gpe_block->register_info[i].status_address); + if (ACPI_FAILURE (status)) { + return (status); + } + /* - * We previously stored the enabled status of all GPEs. - * Blast them back in. + * Restore the GPE Enable register, which will do the following: + * + * 1) Disable all wakeup GPEs + * 2) Enable all runtime GPEs + * + * (On sleep, we saved the enabled status of all GPEs) */ status = acpi_hw_low_level_write (8, gpe_register_info->enable, &gpe_register_info->enable_address); @@ -538,28 +561,30 @@ return (status); } + /* Point to next GPE register */ + gpe_register_info++; } - return (AE_OK); } /****************************************************************************** * - * FUNCTION: acpi_hw_enable_non_wakeup_gpes + * FUNCTION: acpi_hw_restore_gpes_on_wake * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * - * DESCRIPTION: Enable all non-wakeup GPEs we previously enabled. + * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all + * GPE blocks * ******************************************************************************/ acpi_status -acpi_hw_enable_non_wakeup_gpes ( +acpi_hw_restore_gpes_on_wake ( void) { acpi_status status; @@ -568,7 +593,6 @@ ACPI_FUNCTION_ENTRY (); - status = acpi_ev_walk_gpe_list (acpi_hw_enable_non_wakeup_gpe_block); - + status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake); return (status); } diff -urN linux-2.4.25/drivers/acpi/hardware/hwregs.c linux-2.4.26/drivers/acpi/hardware/hwregs.c --- linux-2.4.25/drivers/acpi/hardware/hwregs.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/hardware/hwregs.c 2004-04-14 06:05:28.000000000 -0700 @@ -152,11 +152,11 @@ /* * Evaluate the namespace object containing the values for this state */ - status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_db_sleep_states[sleep_state], + status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], NULL, &obj_desc); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", - acpi_format_exception (status), acpi_gbl_db_sleep_states[sleep_state])); + acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); return_ACPI_STATUS (status); } @@ -201,7 +201,7 @@ if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", - acpi_gbl_db_sleep_states[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); + acpi_gbl_sleep_state_names[sleep_state], obj_desc, acpi_ut_get_object_type_name (obj_desc))); } acpi_ut_remove_reference (obj_desc); diff -urN linux-2.4.25/drivers/acpi/hardware/hwsleep.c linux-2.4.26/drivers/acpi/hardware/hwsleep.c --- linux-2.4.25/drivers/acpi/hardware/hwsleep.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/hardware/hwsleep.c 2004-04-14 06:05:28.000000000 -0700 @@ -48,6 +48,19 @@ ACPI_MODULE_NAME ("hwsleep") +#define METHOD_NAME__BFS "\\_BFS" +#define METHOD_NAME__GTS "\\_GTS" +#define METHOD_NAME__PTS "\\_PTS" +#define METHOD_NAME__SST "\\_SI._SST" +#define METHOD_NAME__WAK "\\_WAK" + +#define ACPI_SST_INDICATOR_OFF 0 +#define ACPI_SST_WORKING 1 +#define ACPI_SST_WAKING 2 +#define ACPI_SST_SLEEPING 3 +#define ACPI_SST_SLEEP_CONTEXT 4 + + /****************************************************************************** * * FUNCTION: acpi_set_firmware_waking_vector @@ -171,19 +184,41 @@ /* Run the _PTS and _GTS methods */ - status = acpi_evaluate_object (NULL, "\\_PTS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__PTS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { return_ACPI_STATUS (status); } - status = acpi_evaluate_object (NULL, "\\_GTS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__GTS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { return_ACPI_STATUS (status); } + /* Setup the argument to _SST */ + + switch (sleep_state) { + case ACPI_STATE_S0: + arg.integer.value = ACPI_SST_WORKING; + break; + + case ACPI_STATE_S1: + case ACPI_STATE_S2: + case ACPI_STATE_S3: + arg.integer.value = ACPI_SST_SLEEPING; + break; + + case ACPI_STATE_S4: + arg.integer.value = ACPI_SST_SLEEP_CONTEXT; + break; + + default: + arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */ + break; + } + /* Set the system indicators to show the desired sleep state. */ - status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); } @@ -251,7 +286,11 @@ } } - status = acpi_hw_disable_non_wakeup_gpes (); + /* + * 1) Disable all runtime GPEs + * 2) Enable all wakeup GPEs + */ + status = acpi_hw_prepare_gpes_for_sleep (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -380,7 +419,11 @@ return_ACPI_STATUS (status); } - status = acpi_hw_disable_non_wakeup_gpes (); + /* + * 1) Disable all runtime GPEs + * 2) Enable all wakeup GPEs + */ + status = acpi_hw_prepare_gpes_for_sleep (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -477,32 +520,53 @@ /* Ignore any errors from these methods */ - arg.integer.value = 0; - status = acpi_evaluate_object (NULL, "\\_SI._SST", &arg_list, NULL); + arg.integer.value = ACPI_SST_WAKING; + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); } arg.integer.value = sleep_state; - status = acpi_evaluate_object (NULL, "\\_BFS", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status))); } - status = acpi_evaluate_object (NULL, "\\_WAK", &arg_list, NULL); + status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL); if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status))); } + /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */ - /* _WAK returns stuff - do we want to look at it? */ - - status = acpi_hw_enable_non_wakeup_gpes (); + /* + * Restore the GPEs: + * 1) Disable all wakeup GPEs + * 2) Enable all runtime GPEs + */ + status = acpi_hw_restore_gpes_on_wake (); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } + /* Enable power button */ + + acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id, + 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id, + 1, ACPI_MTX_DO_NOT_LOCK); + /* Enable BM arbitration */ status = acpi_set_register (ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + arg.integer.value = ACPI_SST_WORKING; + status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL); + if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) { + ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status))); + } + return_ACPI_STATUS (status); } diff -urN linux-2.4.25/drivers/acpi/namespace/nsaccess.c linux-2.4.26/drivers/acpi/namespace/nsaccess.c --- linux-2.4.25/drivers/acpi/namespace/nsaccess.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsaccess.c 2004-04-14 06:05:28.000000000 -0700 @@ -105,8 +105,15 @@ "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { + /* _OSI is optional for now, will be permanent later */ + + if (!ACPI_STRCMP (init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { + continue; + } + status = acpi_ns_lookup (NULL, init_val->name, init_val->type, - ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); + ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, + NULL, &new_node); if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -122,7 +129,8 @@ if (init_val->val) { status = acpi_os_predefined_override (init_val, &val); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not override predefined %s\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not override predefined %s\n", init_val->name)); } @@ -147,15 +155,20 @@ */ switch (init_val->type) { case ACPI_TYPE_METHOD: - obj_desc->method.param_count = - (u8) ACPI_STRTOUL (val, NULL, 10); + obj_desc->method.param_count = (u8) ACPI_STRTOUL + (val, NULL, 10); obj_desc->common.flags |= AOPOBJ_DATA_VALID; -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App) - /* Compiler cheats by putting parameter count in the owner_iD */ + /* i_aSL Compiler cheats by putting parameter count in the owner_iD */ new_node->owner_id = obj_desc->method.param_count; +#else + /* Mark this as a very SPECIAL method */ + + obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; + obj_desc->method.implementation = acpi_ut_osi_implementation; #endif break; @@ -180,8 +193,8 @@ case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; - obj_desc->mutex.sync_level = - (u16) ACPI_STRTOUL (val, NULL, 10); + obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL + (val, NULL, 10); if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { /* @@ -213,6 +226,7 @@ default: + ACPI_REPORT_ERROR (("Unsupported initial type value %X\n", init_val->type)); acpi_ut_remove_reference (obj_desc); @@ -233,6 +247,14 @@ unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + /* Save a handle to "_GPE", it is always present */ + + if (ACPI_SUCCESS (status)) { + status = acpi_ns_get_node_by_path ("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH, + &acpi_gbl_fadt_gpe_device); + } + return_ACPI_STATUS (status); } @@ -314,7 +336,7 @@ else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p Not a namespace node [%s]\n", + ACPI_REPORT_ERROR (("ns_lookup: %p is not a namespace node [%s]\n", prefix_node, acpi_ut_get_descriptor_name (prefix_node))); return_ACPI_STATUS (AE_AML_INTERNAL); } @@ -563,6 +585,7 @@ if ((num_segments == 0) && (type_to_check_for != ACPI_TYPE_ANY) && (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && + (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { diff -urN linux-2.4.25/drivers/acpi/namespace/nsalloc.c linux-2.4.26/drivers/acpi/namespace/nsalloc.c --- linux-2.4.25/drivers/acpi/namespace/nsalloc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsalloc.c 2004-04-14 06:05:28.000000000 -0700 @@ -334,10 +334,11 @@ node->owner_id = owner_id; node->type = (u8) type; - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s (%s) added to %4.4s (%s) %p at %p\n", - acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", + acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id, acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type), - parent_node, node)); + parent_node)); /* * Increment the reference count(s) of all parents up to diff -urN linux-2.4.25/drivers/acpi/namespace/nsdump.c linux-2.4.26/drivers/acpi/namespace/nsdump.c --- linux-2.4.25/drivers/acpi/namespace/nsdump.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsdump.c 2004-04-14 06:05:28.000000000 -0700 @@ -351,6 +351,7 @@ case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: acpi_os_printf ("Target %4.4s (%p)\n", acpi_ut_get_node_name (obj_desc), obj_desc); break; diff -urN linux-2.4.25/drivers/acpi/namespace/nseval.c linux-2.4.26/drivers/acpi/namespace/nseval.c --- linux-2.4.25/drivers/acpi/namespace/nseval.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nseval.c 2004-04-14 06:05:28.000000000 -0700 @@ -82,11 +82,11 @@ union acpi_operand_object **params, union acpi_operand_object **return_object) { - struct acpi_namespace_node *prefix_node; acpi_status status; + struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *node = NULL; + union acpi_generic_state *scope_info; char *internal_path = NULL; - union acpi_generic_state scope_info; ACPI_FUNCTION_TRACE ("ns_evaluate_relative"); @@ -106,11 +106,16 @@ return_ACPI_STATUS (status); } + scope_info = acpi_ut_create_generic_state (); + if (!scope_info) { + goto cleanup1; + } + /* Get the prefix handle and Node */ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } prefix_node = acpi_ns_map_handle_to_node (handle); @@ -122,8 +127,8 @@ /* Lookup the name in the namespace */ - scope_info.scope.node = prefix_node; - status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, + scope_info->scope.node = prefix_node; + status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); @@ -148,7 +153,9 @@ pathname)); cleanup: + acpi_ut_delete_generic_state (scope_info); +cleanup1: ACPI_MEM_FREE (internal_path); return_ACPI_STATUS (status); } @@ -197,7 +204,7 @@ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } /* Lookup the name in the namespace */ @@ -304,6 +311,15 @@ } /* + * For a method alias, we must grab the actual method node + * so that proper scoping context will be established + * before execution. + */ + if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); + } + + /* * Two major cases here: * 1) The object is an actual control method -- execute it. * 2) The object is not a method -- just return it's current diff -urN linux-2.4.25/drivers/acpi/namespace/nssearch.c linux-2.4.26/drivers/acpi/namespace/nssearch.c --- linux-2.4.25/drivers/acpi/namespace/nssearch.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nssearch.c 2004-04-14 06:05:29.000000000 -0700 @@ -113,6 +113,12 @@ /* Check for match against the name */ if (next_node->name.integer == target_name) { + /* Resolve a control method alias if any */ + + if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object); + } + /* * Found matching entry. */ diff -urN linux-2.4.25/drivers/acpi/namespace/nsutils.c linux-2.4.26/drivers/acpi/namespace/nsutils.c --- linux-2.4.25/drivers/acpi/namespace/nsutils.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsutils.c 2004-04-14 06:05:29.000000000 -0700 @@ -256,7 +256,7 @@ if (!node) { - ACPI_REPORT_WARNING (("ns_get_type: Null Node ptr")); + ACPI_REPORT_WARNING (("ns_get_type: Null Node input pointer\n")); return_VALUE (ACPI_TYPE_ANY); } @@ -918,7 +918,7 @@ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto cleanup; } /* Setup lookup scope (search starting point) */ @@ -936,10 +936,10 @@ internal_path, acpi_format_exception (status))); } - /* Cleanup */ - (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); +cleanup: + /* Cleanup */ if (internal_path) { ACPI_MEM_FREE (internal_path); } diff -urN linux-2.4.25/drivers/acpi/namespace/nsxfeval.c linux-2.4.26/drivers/acpi/namespace/nsxfeval.c --- linux-2.4.25/drivers/acpi/namespace/nsxfeval.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsxfeval.c 2004-04-14 06:05:29.000000000 -0700 @@ -45,6 +45,7 @@ #include #include +#include #define _COMPONENT ACPI_NAMESPACE @@ -149,11 +150,11 @@ * FUNCTION: acpi_evaluate_object * * PARAMETERS: Handle - Object handle (optional) - * *Pathname - Object pathname (optional) - * **external_params - List of parameters to pass to method, + * Pathname - Object pathname (optional) + * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. - * *return_buffer - Where to put method's return value (if + * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * * RETURN: Status @@ -172,6 +173,7 @@ struct acpi_buffer *return_buffer) { acpi_status status; + acpi_status status2; union acpi_operand_object **internal_params = NULL; union acpi_operand_object *internal_return_obj = NULL; acpi_size buffer_space_needed; @@ -203,7 +205,7 @@ */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], - &internal_params[i]); + &internal_params[i]); if (ACPI_FAILURE (status)) { acpi_ut_delete_internal_object_list (internal_params); return_ACPI_STATUS (status); @@ -321,14 +323,20 @@ } } - /* Delete the return and parameter objects */ - if (internal_return_obj) { /* - * Delete the internal return object. (Or at least - * decrement the reference count by one) + * Delete the internal return object. NOTE: Interpreter + * must be locked to avoid race condition. */ - acpi_ut_remove_reference (internal_return_obj); + status2 = acpi_ex_enter_interpreter (); + if (ACPI_SUCCESS (status2)) { + /* + * Delete the internal return object. (Or at least + * decrement the reference count by one) + */ + acpi_ut_remove_reference (internal_return_obj); + acpi_ex_exit_interpreter (); + } } /* diff -urN linux-2.4.25/drivers/acpi/namespace/nsxfname.c linux-2.4.26/drivers/acpi/namespace/nsxfname.c --- linux-2.4.25/drivers/acpi/namespace/nsxfname.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/namespace/nsxfname.c 2004-04-14 06:05:29.000000000 -0700 @@ -326,6 +326,13 @@ info.valid |= ACPI_VALID_ADR; } + /* Execute the Device._sx_d methods */ + + status = acpi_ut_execute_sxds (node, info.highest_dstates); + if (ACPI_SUCCESS (status)) { + info.valid |= ACPI_VALID_STA; + } + status = AE_OK; } diff -urN linux-2.4.25/drivers/acpi/osl.c linux-2.4.26/drivers/acpi/osl.c --- linux-2.4.25/drivers/acpi/osl.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/osl.c 2004-04-14 06:05:29.000000000 -0700 @@ -1021,3 +1021,60 @@ } __setup("acpi_os_name=", acpi_os_name_setup); + +/* + * _OSI control + * empty string disables _OSI + * TBD additional string adds to _OSI + */ +int __init +acpi_osi_setup(char *str) +{ + if (str == NULL || *str == '\0') { + printk(KERN_INFO PREFIX "_OSI method disabled\n"); + acpi_gbl_create_osi_method = FALSE; + } else + { + /* TBD */ + printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n", str); + } + + return 1; +} + +__setup("acpi_osi=", acpi_osi_setup); + +/* enable serialization to combat AE_ALREADY_EXISTS errors */ +int __init +acpi_serialize_setup(char *str) +{ + printk(KERN_INFO PREFIX "serialize enabled\n"); + + acpi_gbl_all_methods_serialized = TRUE; + + return 1; +} + +__setup("acpi_serialize", acpi_serialize_setup); + +/* + * Wake and Run-Time GPES are expected to be separate. + * We disable wake-GPEs at run-time to prevent spurious + * interrupts. + * + * However, if a system exists that shares Wake and + * Run-time events on the same GPE this flag is available + * to tell Linux to keep the wake-time GPEs enabled at run-time. + */ +int __init +acpi_wake_gpes_always_on_setup(char *str) +{ + printk(KERN_INFO PREFIX "wake GPEs not disabled\n"); + + acpi_gbl_leave_wake_gpes_disabled = FALSE; + + return 1; +} + +__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); + diff -urN linux-2.4.25/drivers/acpi/parser/psargs.c linux-2.4.26/drivers/acpi/parser/psargs.c --- linux-2.4.25/drivers/acpi/parser/psargs.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/parser/psargs.c 2004-04-14 06:05:29.000000000 -0700 @@ -315,8 +315,8 @@ acpi_ps_append_arg (arg, name_op); if (!method_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, - "Control Method - %p has no attached object\n", + ACPI_REPORT_ERROR (( + "ps_get_next_namepath: Control Method %p has no attached object\n", node)); return_ACPI_STATUS (AE_AML_INTERNAL); } diff -urN linux-2.4.25/drivers/acpi/parser/psparse.c linux-2.4.26/drivers/acpi/parser/psparse.c --- linux-2.4.25/drivers/acpi/parser/psparse.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/parser/psparse.c 2004-04-14 06:05:29.000000000 -0700 @@ -426,7 +426,7 @@ acpi_status status = AE_OK; union acpi_parse_object *op = NULL; /* current op */ union acpi_parse_object *arg = NULL; - union acpi_parse_object pre_op; + union acpi_parse_object *pre_op = NULL; struct acpi_parse_state *parser_state; u8 *aml_op_start = NULL; @@ -547,8 +547,17 @@ /* Create Op structure and append to parent's argument list */ if (walk_state->op_info->flags & AML_NAMED) { - pre_op.common.value.arg = NULL; - pre_op.common.aml_opcode = walk_state->opcode; + /* Allocate a new pre_op if necessary */ + + if (!pre_op) { + pre_op = acpi_ps_alloc_op (walk_state->opcode); + if (!pre_op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + pre_op->common.value.arg = NULL; + pre_op->common.aml_opcode = walk_state->opcode; /* * Get and append arguments until we find the node that contains @@ -562,7 +571,7 @@ goto close_this_op; } - acpi_ps_append_arg (&pre_op, arg); + acpi_ps_append_arg (pre_op, arg); INCREMENT_ARG_LIST (walk_state->arg_types); } @@ -603,7 +612,7 @@ goto close_this_op; } - acpi_ps_append_arg (op, pre_op.common.value.arg); + acpi_ps_append_arg (op, pre_op->common.value.arg); acpi_gbl_depth++; if (op->common.aml_opcode == AML_REGION_OP) { @@ -854,6 +863,10 @@ acpi_ps_complete_this_op (walk_state, op); op = NULL; + if (pre_op) { + acpi_ps_free_op (pre_op); + pre_op = NULL; + } switch (status) { case AE_OK: @@ -1118,6 +1131,27 @@ else if (status != AE_OK) { ACPI_REPORT_METHOD_ERROR ("Method execution failed", walk_state->method_node, NULL, status); + + /* Check for possible multi-thread reentrancy problem */ + + if ((status == AE_ALREADY_EXISTS) && + (!walk_state->method_desc->method.semaphore)) { + /* + * This method is marked not_serialized, but it tried to create a named + * object, causing the second thread entrance to fail. We will workaround + * this by marking the method permanently as Serialized. + */ + walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED; + walk_state->method_desc->method.concurrency = 1; + } + } + + if (walk_state->method_desc) { + /* Decrement the thread count on the method parse tree */ + + if (walk_state->method_desc->method.thread_count) { + walk_state->method_desc->method.thread_count--; + } } /* We are done with this walk, move on to the parent if any */ diff -urN linux-2.4.25/drivers/acpi/parser/psscope.c linux-2.4.26/drivers/acpi/parser/psscope.c --- linux-2.4.25/drivers/acpi/parser/psscope.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/parser/psscope.c 2004-04-14 06:05:29.000000000 -0700 @@ -167,7 +167,6 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; scope->parse_scope.op = op; scope->parse_scope.arg_list = remaining_args; @@ -178,13 +177,11 @@ acpi_ut_push_generic_state (&parser_state->scope, scope); - if (arg_count == ACPI_VAR_ARGS) { /* multiple arguments */ scope->parse_scope.arg_end = parser_state->pkg_end; } - else { /* single argument */ @@ -241,7 +238,6 @@ acpi_ut_delete_generic_state (scope); } - else { /* empty parse stack, prepare to fetch next opcode */ @@ -250,7 +246,6 @@ *arg_count = 0; } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count)); return_VOID; } @@ -275,14 +270,14 @@ { union acpi_generic_state *scope; + ACPI_FUNCTION_TRACE_PTR ("ps_cleanup_scope", parser_state); if (!parser_state) { - return; + return_VOID; } - /* Delete anything on the scope stack */ while (parser_state->scope) { diff -urN linux-2.4.25/drivers/acpi/pci_irq.c linux-2.4.26/drivers/acpi/pci_irq.c --- linux-2.4.25/drivers/acpi/pci_irq.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/pci_irq.c 2004-04-14 06:05:29.000000000 -0700 @@ -277,7 +277,6 @@ return_VALUE(entry->irq); } - static int acpi_pci_irq_derive ( struct pci_dev *dev, @@ -285,6 +284,7 @@ { struct pci_dev *bridge = dev; int irq = 0; + u8 bridge_pin = 0; ACPI_FUNCTION_TRACE("acpi_pci_irq_derive"); @@ -293,12 +293,28 @@ /* * Attempt to derive an IRQ for this device from a parent bridge's - * PCI interrupt routing entry (a.k.a. the "bridge swizzle"). + * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge) */ while (!irq && bridge->bus->self) { pin = (pin + PCI_SLOT(bridge->devfn)) % 4; bridge = bridge->bus->self; - irq = acpi_pci_irq_lookup(0, bridge->bus->number, PCI_SLOT(bridge->devfn), pin); + + if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { + /* PC card has the same IRQ as its cardbridge */ + pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, &bridge_pin); + if (!bridge_pin) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No interrupt pin configured for device %s\n", + pci_name(bridge))); + return_VALUE(0); + } + /* Pin is from 0 to 3 */ + bridge_pin --; + pin = bridge_pin; + } + + irq = acpi_pci_irq_lookup(0, bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); } if (!irq) { @@ -306,7 +322,8 @@ return_VALUE(0); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived IRQ %d\n", irq)); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", + irq, pci_name(dev), pci_name(bridge))); return_VALUE(irq); } diff -urN linux-2.4.25/drivers/acpi/pci_link.c linux-2.4.26/drivers/acpi/pci_link.c --- linux-2.4.25/drivers/acpi/pci_link.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/drivers/acpi/pci_link.c 2004-04-14 06:05:29.000000000 -0700 @@ -68,6 +68,7 @@ u8 edge_level; /* All IRQs */ u8 active_high_low; /* All IRQs */ u8 setonboot; + u8 resource_type; u8 possible_count; u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; }; @@ -119,6 +120,7 @@ } link->irq.edge_level = p->edge_level; link->irq.active_high_low = p->active_high_low; + link->irq.resource_type = ACPI_RSTYPE_IRQ; break; } case ACPI_RSTYPE_EXT_IRQ: @@ -139,6 +141,7 @@ } link->irq.edge_level = p->edge_level; link->irq.active_high_low = p->active_high_low; + link->irq.resource_type = ACPI_RSTYPE_EXT_IRQ; break; } default: @@ -338,13 +341,18 @@ } } + resource_type = link->irq.resource_type; + + if (resource_type != ACPI_RSTYPE_IRQ && + resource_type != ACPI_RSTYPE_EXT_IRQ){ /* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with * an extended one */ - if (irq <= 15) { - resource_type = ACPI_RSTYPE_IRQ; - } else { - resource_type = ACPI_RSTYPE_EXT_IRQ; - } + if (irq <= 15) { + resource_type = ACPI_RSTYPE_IRQ; + } else { + resource_type = ACPI_RSTYPE_EXT_IRQ; + } + } retry_programming: @@ -767,7 +775,6 @@ static int __init acpi_irq_nobalance_set(char *str) { -printk("ACPI STATIC SET\n"); acpi_irq_balance = 0; return(1); } @@ -775,7 +782,6 @@ int __init acpi_irq_balance_set(char *str) { -printk("ACPI BALANCE SET\n"); acpi_irq_balance = 1; return(1); } diff -urN linux-2.4.25/drivers/acpi/processor.c linux-2.4.26/drivers/acpi/processor.c --- linux-2.4.25/drivers/acpi/processor.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/processor.c 2004-04-14 06:05:29.000000000 -0700 @@ -69,8 +69,6 @@ #define ACPI_PROCESSOR_MAX_THROTTLE 250 /* 25% */ #define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4 -const u32 POWER_OF_2[] = {1,2,4,8,16,32,64}; - #define ACPI_PROCESSOR_LIMIT_USER 0 #define ACPI_PROCESSOR_LIMIT_THERMAL 1 @@ -1377,7 +1375,7 @@ return_VALUE(0); } - pr->throttling.state_count = POWER_OF_2[acpi_fadt.duty_width]; + pr->throttling.state_count = 1 << acpi_fadt.duty_width; /* * Compute state values. Note that throttling displays a linear power/ diff -urN linux-2.4.25/drivers/acpi/resources/rsaddr.c linux-2.4.26/drivers/acpi/resources/rsaddr.c --- linux-2.4.25/drivers/acpi/resources/rsaddr.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/resources/rsaddr.c 2004-04-14 06:05:29.000000000 -0700 @@ -88,6 +88,7 @@ ACPI_FUNCTION_TRACE ("rs_address16_resource"); + /* * Point past the Descriptor to get the number of bytes consumed */ @@ -149,7 +150,7 @@ output_struct->data.address16.attribute.memory.read_write_attribute = (u16) (temp8 & 0x01); output_struct->data.address16.attribute.memory.cache_attribute = - (u16) ((temp8 >> 1) & 0x0F); + (u16) ((temp8 >> 1) & 0x03); } else { if (ACPI_IO_RANGE == output_struct->data.address16.resource_type) { @@ -347,7 +348,7 @@ temp8 |= (linked_list->data.address16.attribute.memory.cache_attribute & - 0x0F) << 1; + 0x03) << 1; } else if (ACPI_IO_RANGE == linked_list->data.address16.resource_type) { temp8 = (u8) @@ -539,7 +540,7 @@ (u16) (temp8 & 0x01); output_struct->data.address32.attribute.memory.cache_attribute = - (u16) ((temp8 >> 1) & 0x0F); + (u16) ((temp8 >> 1) & 0x03); } else { if (ACPI_IO_RANGE == output_struct->data.address32.resource_type) { @@ -735,7 +736,7 @@ temp8 |= (linked_list->data.address32.attribute.memory.cache_attribute & - 0x0F) << 1; + 0x03) << 1; } else if (ACPI_IO_RANGE == linked_list->data.address32.resource_type) { temp8 = (u8) @@ -926,7 +927,7 @@ (u16) (temp8 & 0x01); output_struct->data.address64.attribute.memory.cache_attribute = - (u16) ((temp8 >> 1) & 0x0F); + (u16) ((temp8 >> 1) & 0x03); } else { if (ACPI_IO_RANGE == output_struct->data.address64.resource_type) { @@ -1124,7 +1125,7 @@ temp8 |= (linked_list->data.address64.attribute.memory.cache_attribute & - 0x0F) << 1; + 0x03) << 1; } else if (ACPI_IO_RANGE == linked_list->data.address64.resource_type) { temp8 = (u8) diff -urN linux-2.4.25/drivers/acpi/resources/rsxface.c linux-2.4.26/drivers/acpi/resources/rsxface.c --- linux-2.4.25/drivers/acpi/resources/rsxface.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/resources/rsxface.c 2004-04-14 06:05:29.000000000 -0700 @@ -239,6 +239,7 @@ acpi_status status; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *resource; + struct acpi_resource *buffer_end; ACPI_FUNCTION_TRACE ("acpi_walk_resources"); @@ -255,7 +256,13 @@ return_ACPI_STATUS (status); } - resource = (struct acpi_resource *) buffer.pointer; + /* Setup pointers */ + + resource = (struct acpi_resource *) buffer.pointer; + buffer_end = (struct acpi_resource *) ((u8 *) buffer.pointer + buffer.length); + + /* Walk the resource list */ + for (;;) { if (!resource || resource->id == ACPI_RSTYPE_END_TAG) { break; @@ -268,6 +275,7 @@ case AE_CTRL_DEPTH: /* Just keep going */ + status = AE_OK; break; @@ -285,7 +293,15 @@ goto cleanup; } + /* Get the next resource descriptor */ + resource = ACPI_NEXT_RESOURCE (resource); + + /* Check for end-of-buffer */ + + if (resource >= buffer_end) { + goto cleanup; + } } cleanup: diff -urN linux-2.4.25/drivers/acpi/system.c linux-2.4.26/drivers/acpi/system.c --- linux-2.4.25/drivers/acpi/system.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/drivers/acpi/system.c 2004-04-14 06:05:29.000000000 -0700 @@ -40,15 +40,20 @@ #include #include #include +#include -#ifdef CONFIG_X86 #ifdef CONFIG_ACPI_SLEEP #include #include #include -#endif -#endif +acpi_status acpi_system_save_state(u32); +#else +static inline acpi_status acpi_system_save_state(u32 state) +{ + return AE_OK; +} +#endif /* !CONFIG_ACPI_SLEEP */ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME ("acpi_system") @@ -95,6 +100,9 @@ { if (unlikely(in_interrupt())) BUG(); + /* Some SMP machines only can poweroff in boot CPU */ + set_cpus_allowed(current, 1UL << cpu_logical_map(0)); + acpi_system_save_state(ACPI_STATE_S5); acpi_enter_sleep_state_prep(ACPI_STATE_S5); ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); diff -urN linux-2.4.25/drivers/acpi/toshiba_acpi.c linux-2.4.26/drivers/acpi/toshiba_acpi.c --- linux-2.4.25/drivers/acpi/toshiba_acpi.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/toshiba_acpi.c 2004-04-14 06:05:29.000000000 -0700 @@ -33,7 +33,7 @@ * */ -#define TOSHIBA_ACPI_VERSION "0.17" +#define TOSHIBA_ACPI_VERSION "0.18" #define PROC_INTERFACE_VERSION 1 #include @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -106,24 +107,6 @@ *word = (*word & ~mask) | (mask * value); } -/* an sscanf that takes explicit string length */ -static int -snscanf(const char* str, int n, const char* format, ...) -{ - va_list args; - int result; - char* str2 = kmalloc(n + 1, GFP_KERNEL); - if (str2 == 0) return 0; - /* NOTE: don't even _think_ about replacing this with strlcpy */ - strncpy(str2, str, n); - str2[n] = 0; - va_start(args, format); - result = vsscanf(str2, format, args); - va_end(args); - kfree(str2); - return result; -} - /* acpi interface wrappers */ @@ -270,10 +253,26 @@ } static int -dispatch_write(struct file* file, const char* buffer, unsigned long count, - ProcItem* item) +dispatch_write(struct file* file, const char* buffer, + unsigned long count, ProcItem* item) { - return item->write_func(buffer, count); + int result; + char* tmp_buffer; + + /* Arg buffer points to userspace memory, which can't be accessed + * directly. Since we're making a copy, zero-terminate the + * destination so that sscanf can be used on it safely. + */ + tmp_buffer = kmalloc(count + 1, GFP_KERNEL); + if (copy_from_user(tmp_buffer, buffer, count)) { + result = -EFAULT; + } + else { + tmp_buffer[count] = 0; + result = item->write_func(tmp_buffer, count); + } + kfree(tmp_buffer); + return result; } static char* @@ -301,7 +300,7 @@ int value; u32 hci_result; - if (snscanf(buffer, count, " brightness : %i", &value) == 1 && + if (sscanf(buffer, " brightness : %i", &value) == 1 && value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { value = value << HCI_LCD_BRIGHTNESS_SHIFT; hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result); @@ -351,11 +350,11 @@ * NOTE: to keep scanning simple, invalid fields are ignored */ while (remain) { - if (snscanf(buffer, remain, " lcd_out : %i", &value) == 1) + if (sscanf(buffer, " lcd_out : %i", &value) == 1) lcd_out = value & 1; - else if (snscanf(buffer, remain, " crt_out : %i", &value) == 1) + else if (sscanf(buffer, " crt_out : %i", &value) == 1) crt_out = value & 1; - else if (snscanf(buffer, remain, " tv_out : %i", &value) == 1) + else if (sscanf(buffer, " tv_out : %i", &value) == 1) tv_out = value & 1; /* advance to one character past the next ; */ do { @@ -408,7 +407,7 @@ int value; u32 hci_result; - if (snscanf(buffer, count, " force_on : %i", &value) == 1 && + if (sscanf(buffer, " force_on : %i", &value) == 1 && value >= 0 && value <= 1) { hci_write1(HCI_FAN, value, &hci_result); if (hci_result != HCI_SUCCESS) @@ -459,7 +458,7 @@ { int value; - if (snscanf(buffer, count, " hotkey_ready : %i", &value) == 1 && + if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) { key_event_valid = 0; } else { diff -urN linux-2.4.25/drivers/acpi/utilities/uteval.c linux-2.4.26/drivers/acpi/utilities/uteval.c --- linux-2.4.25/drivers/acpi/utilities/uteval.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/utilities/uteval.c 2004-04-14 06:05:29.000000000 -0700 @@ -53,6 +53,62 @@ /******************************************************************************* * + * FUNCTION: acpi_ut_osi_implementation + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Implementation of _OSI predefined control method + * Supported = _OSI (String) + * + ******************************************************************************/ + +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *string_desc; + union acpi_operand_object *return_desc; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ut_osi_implementation"); + + + /* Validate the string input argument */ + + string_desc = walk_state->arguments[0].object; + if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { + return_ACPI_STATUS (AE_TYPE); + } + + /* Create a return object (Default value = 0) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Compare input string to table of supported strings */ + + for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) { + if (!ACPI_STRCMP (string_desc->string.pointer, + (char *) acpi_gbl_valid_osi_strings[i])) { + /* This string is supported */ + + return_desc->integer.value = 0xFFFFFFFF; + break; + } + } + + walk_state->return_desc = return_desc; + return_ACPI_STATUS (AE_CTRL_TERMINATE); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ut_evaluate_object * * PARAMETERS: prefix_node - Starting node @@ -562,3 +618,63 @@ acpi_ut_remove_reference (obj_desc); return_ACPI_STATUS (status); } + + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_Sxds + * + * PARAMETERS: device_node - Node for the device + * *Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 i; + + + ACPI_FUNCTION_TRACE ("ut_execute_Sxds"); + + + for (i = 0; i < 4; i++) { + highest[i] = 0xFF; + status = acpi_ut_evaluate_object (device_node, + (char *) acpi_gbl_highest_dstate_names[i], + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE (status)) { + if (status != AE_NOT_FOUND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s on Device %4.4s, %s\n", + (char *) acpi_gbl_highest_dstate_names[i], + acpi_ut_get_node_name (device_node), + acpi_format_exception (status))); + + return_ACPI_STATUS (status); + } + } + else { + /* Extract the Dstate value */ + + highest[i] = (u8) obj_desc->integer.value; + + /* Delete the return object */ + + acpi_ut_remove_reference (obj_desc); + } + } + + return_ACPI_STATUS (AE_OK); +} diff -urN linux-2.4.25/drivers/acpi/utilities/utglobal.c linux-2.4.26/drivers/acpi/utilities/utglobal.c --- linux-2.4.25/drivers/acpi/utilities/utglobal.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/utilities/utglobal.c 2004-04-14 06:05:29.000000000 -0700 @@ -171,7 +171,7 @@ const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128}; -const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT] = { +const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", "\\_S2_", @@ -179,6 +179,20 @@ "\\_S4_", "\\_S5_"}; +const char *acpi_gbl_highest_dstate_names[4] = { + "_S1D", + "_S2D", + "_S3D", + "_S4D"}; + +/* Strings supported by the _OSI predefined (internal) method */ + +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1"}; + /****************************************************************************** * @@ -190,14 +204,10 @@ /* * Predefined ACPI Names (Built-in to the Interpreter) * - * Initial values are currently supported only for types String and Number. - * Both are specified as strings in this table. - * * NOTES: - * 1) _SB_ is defined to be a device to allow _SB_/_INI to be run + * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run * during the initialization sequence. */ - const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, @@ -208,7 +218,7 @@ {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) {"_OSI", ACPI_TYPE_METHOD, "1"}, #endif {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ @@ -219,7 +229,6 @@ * Properties of the ACPI Object Types, both internal and external. * The table is indexed by values of acpi_object_type */ - const u8 acpi_gbl_ns_properties[] = { ACPI_NS_NORMAL, /* 00 Any */ @@ -244,14 +253,15 @@ ACPI_NS_NORMAL, /* 19 index_field */ ACPI_NS_NORMAL, /* 20 Reference */ ACPI_NS_NORMAL, /* 21 Alias */ - ACPI_NS_NORMAL, /* 22 Notify */ - ACPI_NS_NORMAL, /* 23 Address Handler */ - ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 24 Resource Desc */ - ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Field */ - ACPI_NS_NEWSCOPE, /* 26 Scope */ - ACPI_NS_NORMAL, /* 27 Extra */ - ACPI_NS_NORMAL, /* 28 Data */ - ACPI_NS_NORMAL /* 29 Invalid */ + ACPI_NS_NORMAL, /* 22 method_alias */ + ACPI_NS_NORMAL, /* 23 Notify */ + ACPI_NS_NORMAL, /* 24 Address Handler */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ + ACPI_NS_NEWSCOPE, /* 27 Scope */ + ACPI_NS_NORMAL, /* 28 Extra */ + ACPI_NS_NORMAL, /* 29 Data */ + ACPI_NS_NORMAL /* 30 Invalid */ }; @@ -298,10 +308,8 @@ * ******************************************************************************/ - struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES]; - struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] = { /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ @@ -465,9 +473,8 @@ * * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when * stored in a table it really means that we have thus far seen no evidence to - * indicatewhat type is actually going to be stored for this entry. + * indicate what type is actually going to be stored for this entry. */ - static const char acpi_gbl_bad_type[] = "UNDEFINED"; #define TYPE_NAME_LENGTH 12 /* Maximum length of each string */ @@ -495,14 +502,15 @@ /* 19 */ "index_field", /* 20 */ "Reference", /* 21 */ "Alias", - /* 22 */ "Notify", - /* 23 */ "addr_handler", - /* 24 */ "resource_desc", - /* 25 */ "resource_fld", - /* 26 */ "Scope", - /* 27 */ "Extra", - /* 28 */ "Data", - /* 39 */ "Invalid" + /* 22 */ "method_alias", + /* 23 */ "Notify", + /* 24 */ "addr_handler", + /* 25 */ "resource_desc", + /* 26 */ "resource_fld", + /* 27 */ "Scope", + /* 28 */ "Extra", + /* 29 */ "Data", + /* 30 */ "Invalid" }; @@ -550,7 +558,7 @@ acpi_ut_get_node_name ( void *object) { - struct acpi_namespace_node *node; + struct acpi_namespace_node *node = (struct acpi_namespace_node *) object; if (!object) @@ -558,7 +566,10 @@ return ("NULL NODE"); } - node = (struct acpi_namespace_node *) object; + if (object == ACPI_ROOT_OBJECT) + { + node = acpi_gbl_root_node; + } if (node->descriptor != ACPI_DESC_TYPE_NAMED) { @@ -772,6 +783,12 @@ ACPI_FUNCTION_TRACE ("ut_init_globals"); + /* Runtime configuration */ + + acpi_gbl_create_osi_method = TRUE; + acpi_gbl_all_methods_serialized = FALSE; + acpi_gbl_leave_wake_gpes_disabled = TRUE; + /* Memory allocation and cache lists */ ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (struct acpi_memory_list) * ACPI_NUM_MEM_LISTS); diff -urN linux-2.4.25/drivers/acpi/utilities/utmisc.c linux-2.4.26/drivers/acpi/utilities/utmisc.c --- linux-2.4.25/drivers/acpi/utilities/utmisc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/acpi/utilities/utmisc.c 2004-04-14 06:05:29.000000000 -0700 @@ -529,6 +529,7 @@ return (src_string); } + /******************************************************************************* * * FUNCTION: acpi_ut_mutex_initialize @@ -562,10 +563,8 @@ } } - status = acpi_os_create_lock (&acpi_gbl_gpe_lock); - - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } diff -urN linux-2.4.25/drivers/atm/nicstar.c linux-2.4.26/drivers/atm/nicstar.c --- linux-2.4.25/drivers/atm/nicstar.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/atm/nicstar.c 2004-04-14 06:05:29.000000000 -0700 @@ -112,9 +112,6 @@ /* Macros *********************************************************************/ -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - #define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) #define NS_DELAY mdelay(1) @@ -2472,7 +2469,7 @@ for (j = 1; j < NS_SKB(iovb)->iovcnt; j++) { lb = (struct sk_buff *) iov->iov_base; - tocopy = MIN(remaining, iov->iov_len); + tocopy = min_t(int, remaining, iov->iov_len); memcpy(hb->tail, lb->data, tocopy); skb_put(hb, tocopy); iov++; diff -urN linux-2.4.25/drivers/block/cciss.c linux-2.4.26/drivers/block/cciss.c --- linux-2.4.25/drivers/block/cciss.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/block/cciss.c 2004-04-14 06:05:29.000000000 -0700 @@ -508,12 +508,8 @@ driver_geo.heads = hba[ctlr]->drv[dsk].heads; driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; - } else { - driver_geo.heads = 0xff; - driver_geo.sectors = 0x3f; - driver_geo.cylinders = - hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); - } + } else + return -ENXIO; driver_geo.start= hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect; if (copy_to_user((void *) arg, &driver_geo, @@ -528,12 +524,8 @@ driver_geo.heads = hba[ctlr]->drv[dsk].heads; driver_geo.sectors = hba[ctlr]->drv[dsk].sectors; driver_geo.cylinders = hba[ctlr]->drv[dsk].cylinders; - } else { - driver_geo.heads = 0xff; - driver_geo.sectors = 0x3f; - driver_geo.cylinders = - hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); - } + } else + return -ENXIO; driver_geo.start= hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect; if (copy_to_user((void *) arg, &driver_geo, diff -urN linux-2.4.25/drivers/block/cciss_scsi.c linux-2.4.26/drivers/block/cciss_scsi.c --- linux-2.4.25/drivers/block/cciss_scsi.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.26/drivers/block/cciss_scsi.c 2004-04-14 06:05:29.000000000 -0700 @@ -589,6 +589,8 @@ for(i=0; iLUN[i][3] & 0xC0) continue; memset(inq_buff, 0, sizeof(InquiryData_struct)); memcpy(scsi3addr, ld_buff->LUN[i], 8); /* ugly... */ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, @@ -1148,6 +1150,7 @@ int devtype; /* for each physical lun, do an inquiry */ + if (ld_buff->LUN[i][3] & 0xC0) continue; memset(inq_buff, 0, sizeof(InquiryData_struct)); memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8); diff -urN linux-2.4.25/drivers/block/ll_rw_blk.c linux-2.4.26/drivers/block/ll_rw_blk.c --- linux-2.4.25/drivers/block/ll_rw_blk.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/block/ll_rw_blk.c 2004-04-14 06:05:29.000000000 -0700 @@ -942,6 +942,15 @@ return; q->elevator.elevator_merge_req_fn(req, next); + + /* At this point we have either done a back merge + * or front merge. We need the smaller start_time of + * the merged requests to be the current request + * for accounting purposes. + */ + if (time_after(req->start_time, next->start_time)) + req->start_time = next->start_time; + req->bhtail->b_reqnext = next->bh; req->bhtail = next->bhtail; req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; diff -urN linux-2.4.25/drivers/bluetooth/hci_usb.c linux-2.4.26/drivers/bluetooth/hci_usb.c --- linux-2.4.25/drivers/bluetooth/hci_usb.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/bluetooth/hci_usb.c 2004-04-14 06:05:29.000000000 -0700 @@ -30,7 +30,7 @@ * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $ */ -#define VERSION "2.4" +#define VERSION "2.5" #include #include @@ -70,12 +70,12 @@ static struct usb_driver hci_usb_driver; static struct usb_device_id bluetooth_ids[] = { - /* Digianswer device */ - { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER }, - /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, + /* AVM BlueFRITZ! USB v2.0 */ + { USB_DEVICE(0x057c, 0x3800) }, + /* Ericsson with non-standard id */ { USB_DEVICE(0x0bdb, 0x1002) }, @@ -90,9 +90,15 @@ MODULE_DEVICE_TABLE (usb, bluetooth_ids); -static struct usb_device_id ignore_ids[] = { +static struct usb_device_id blacklist_ids[] = { /* Broadcom BCM2033 without firmware */ - { USB_DEVICE(0x0a5c, 0x2033) }, + { USB_DEVICE(0x0a5c, 0x2033), driver_info: HCI_IGNORE }, + + /* Broadcom BCM2035 */ + { USB_DEVICE(0x0a5c, 0x200a), driver_info: HCI_RESET }, + + /* Digianswer device */ + { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER }, { } /* Terminating entry */ }; @@ -648,7 +654,7 @@ #endif } BT_DBG("new packet len %d", len); - + skb = bluez_skb_alloc(len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for the packet", husb->hdev.name); @@ -796,8 +802,14 @@ iface = &udev->actconfig->interface[0]; - /* Check our black list */ - if (usb_match_id(udev, iface, ignore_ids)) + if (!id->driver_info) { + const struct usb_device_id *match; + match = usb_match_id(udev, iface, blacklist_ids); + if (match) + id = match; + } + + if (id->driver_info & HCI_IGNORE) return NULL; /* Check number of endpoints */ @@ -921,6 +933,9 @@ hdev->send = hci_usb_send_frame; hdev->destruct = hci_usb_destruct; + if (id->driver_info & HCI_RESET) + set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); goto probe_error; @@ -983,6 +998,6 @@ module_init(hci_usb_init); module_exit(hci_usb_cleanup); -MODULE_AUTHOR("Maxim Krasnyansky "); +MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION); MODULE_LICENSE("GPL"); diff -urN linux-2.4.25/drivers/bluetooth/hci_usb.h linux-2.4.26/drivers/bluetooth/hci_usb.h --- linux-2.4.25/drivers/bluetooth/hci_usb.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/bluetooth/hci_usb.h 2004-04-14 06:05:29.000000000 -0700 @@ -37,7 +37,9 @@ #define HCI_CTRL_REQ 0x20 #define HCI_DIGI_REQ 0x40 -#define HCI_DIGIANSWER 0x01 +#define HCI_IGNORE 0x01 +#define HCI_RESET 0x02 +#define HCI_DIGIANSWER 0x04 #define HCI_MAX_IFACE_NUM 3 diff -urN linux-2.4.25/drivers/char/agp/agpgart_be.c linux-2.4.26/drivers/char/agp/agpgart_be.c --- linux-2.4.25/drivers/char/agp/agpgart_be.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/char/agp/agpgart_be.c 2004-04-14 06:05:29.000000000 -0700 @@ -6181,12 +6181,6 @@ "SiS", "650", sis_generic_setup }, - { PCI_DEVICE_ID_SI_651, - PCI_VENDOR_ID_SI, - SIS_GENERIC, - "SiS", - "651", - sis_generic_setup }, { PCI_DEVICE_ID_SI_645, PCI_VENDOR_ID_SI, SIS_GENERIC, diff -urN linux-2.4.25/drivers/char/drm/r128_state.c linux-2.4.26/drivers/char/drm/r128_state.c --- linux-2.4.25/drivers/char/drm/r128_state.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/char/drm/r128_state.c 2004-04-14 06:05:29.000000000 -0700 @@ -914,7 +914,7 @@ count = depth->n; - if( count > 4096 ) + if( count > 4096 || count <= 0) return -EMSGSIZE; if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { return -EFAULT; @@ -1010,7 +1010,7 @@ count = depth->n; - if( count > 4096 ) + if( count > 4096 || count <= 0) return -EMSGSIZE; x = kmalloc( count * sizeof(*x), GFP_KERNEL ); @@ -1128,7 +1128,7 @@ count = depth->n; - if ( count > 4096 ) + if ( count > 4096 || count <= 0) return -EMSGSIZE; if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { return -EFAULT; @@ -1172,6 +1172,9 @@ DRM_DEBUG( "%s\n", __FUNCTION__ ); count = depth->n; + if ( count > 4096 || count <= 0) + return -EMSGSIZE; + if ( count > dev_priv->depth_pitch ) { count = dev_priv->depth_pitch; } diff -urN linux-2.4.25/drivers/char/drm-4.0/r128_state.c linux-2.4.26/drivers/char/drm-4.0/r128_state.c --- linux-2.4.25/drivers/char/drm-4.0/r128_state.c 2002-02-25 11:37:57.000000000 -0800 +++ linux-2.4.26/drivers/char/drm-4.0/r128_state.c 2004-04-14 06:05:29.000000000 -0700 @@ -938,6 +938,9 @@ } count = depth->n; + + if (count > 4096 || count <= 0) + return -EMSGSIZE; if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { return -EFAULT; } @@ -1048,6 +1051,9 @@ count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; + x = kmalloc( count * sizeof(*x), 0 ); if ( x == NULL ) { return -ENOMEM; @@ -1178,6 +1184,10 @@ } count = depth->n; + + if (count > 4096 || count <= 0) + return -EMSGSIZE; + if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { return -EFAULT; } @@ -1235,6 +1245,8 @@ } count = depth->n; + if (count > 4096 || count <= 0) + return -EMSGSIZE; if ( count > dev_priv->depth_pitch ) { count = dev_priv->depth_pitch; } diff -urN linux-2.4.25/drivers/char/q40_keyb.c linux-2.4.26/drivers/char/q40_keyb.c --- linux-2.4.25/drivers/char/q40_keyb.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.26/drivers/char/q40_keyb.c 2004-04-14 06:05:29.000000000 -0700 @@ -400,7 +400,7 @@ #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ -static int __init kbd_read_input(void) +static int __init q40kbd_read_input(void) { int retval = KBD_NO_DATA; unsigned char status; @@ -421,7 +421,7 @@ int maxread = 100; /* Random number */ do { - if (kbd_read_input() == KBD_NO_DATA) + if (q40kbd_read_input() == KBD_NO_DATA) break; } while (--maxread); } diff -urN linux-2.4.25/drivers/char/sonypi.c linux-2.4.26/drivers/char/sonypi.c --- linux-2.4.25/drivers/char/sonypi.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/char/sonypi.c 2004-04-14 06:05:29.000000000 -0700 @@ -129,7 +129,7 @@ } /* Initializes the device - this comes from the AML code in the ACPI bios */ -static void __devinit sonypi_type1_srs(void) { +static void sonypi_type1_srs(void) { u32 v; pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); @@ -151,7 +151,7 @@ pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); } -static void __devinit sonypi_type2_srs(void) { +static void sonypi_type2_srs(void) { if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8)) printk(KERN_WARNING "ec_write failed\n"); if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF)) diff -urN linux-2.4.25/drivers/char/sonypi.h linux-2.4.26/drivers/char/sonypi.h --- linux-2.4.25/drivers/char/sonypi.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/char/sonypi.h 2004-04-14 06:05:29.000000000 -0700 @@ -37,7 +37,7 @@ #ifdef __KERNEL__ #define SONYPI_DRIVER_MAJORVERSION 1 -#define SONYPI_DRIVER_MINORVERSION 21 +#define SONYPI_DRIVER_MINORVERSION 22 #define SONYPI_DEVICE_MODEL_TYPE1 1 #define SONYPI_DEVICE_MODEL_TYPE2 2 @@ -239,6 +239,7 @@ { 0x01, SONYPI_EVENT_PKEY_P1 }, { 0x02, SONYPI_EVENT_PKEY_P2 }, { 0x04, SONYPI_EVENT_PKEY_P3 }, + { 0x5c, SONYPI_EVENT_PKEY_P1 }, { 0, 0 } }; @@ -333,6 +334,7 @@ { SONYPI_DEVICE_MODEL_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, { SONYPI_DEVICE_MODEL_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, + { SONYPI_DEVICE_MODEL_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0, 0, 0, 0 } }; @@ -394,7 +396,6 @@ } #ifdef CONFIG_ACPI -extern int acpi_disabled; #define SONYPI_ACPI_ACTIVE (!acpi_disabled) #else #define SONYPI_ACPI_ACTIVE 0 diff -urN linux-2.4.25/drivers/char/tty_io.c linux-2.4.26/drivers/char/tty_io.c --- linux-2.4.25/drivers/char/tty_io.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/char/tty_io.c 2004-04-14 06:05:29.000000000 -0700 @@ -2249,7 +2249,7 @@ au1x00_serial_console_init(); #endif #ifdef CONFIG_SERIAL_CONSOLE -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +#if (defined(CONFIG_8xx) || defined(CONFIG_CPM2)) console_8xx_init(); #elif defined(CONFIG_MAC_SERIAL) && defined(CONFIG_SERIAL) if (_machine == _MACH_Pmac) @@ -2435,7 +2435,7 @@ #ifdef CONFIG_SPECIALIX specialix_init(); #endif -#if (defined(CONFIG_8xx) || defined(CONFIG_8260)) +#if (defined(CONFIG_8xx) || defined(CONFIG_CPM2)) rs_8xx_init(); #endif /* CONFIG_8xx */ pty_init(); diff -urN linux-2.4.25/drivers/i2c/Config.in linux-2.4.26/drivers/i2c/Config.in --- linux-2.4.25/drivers/i2c/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/i2c/Config.in 2004-04-14 06:05:29.000000000 -0700 @@ -12,7 +12,7 @@ dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT dep_tristate ' Velleman K8000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT - dep_tristate ' NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT + dep_tristate ' NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200_GPIO $CONFIG_I2C_ALGOBIT if [ "$CONFIG_SCx200_I2C" != "n" ]; then int ' GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12 int ' GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13 diff -urN linux-2.4.25/drivers/ide/Config.in linux-2.4.26/drivers/ide/Config.in --- linux-2.4.25/drivers/ide/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/ide/Config.in 2004-04-14 06:05:29.000000000 -0700 @@ -49,6 +49,7 @@ dep_mbool ' ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3 dep_tristate ' AMD and nVidia IDE support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI dep_mbool ' AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX + dep_tristate ' ATI IXP chipset IDE support' CONFIG_BLK_DEV_ATIIXP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86 dep_tristate ' CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' Compaq Triflex IDE support' CONFIG_BLK_DEV_TRIFLEX $CONFIG_BLK_DEV_IDEDMA_PCI dep_tristate ' CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI @@ -190,6 +191,7 @@ dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL dep_tristate ' Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID dep_tristate ' Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID +dep_tristate ' CMD/Silicon Image Medley Software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_MEDLEY $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID dep_tristate ' Silicon Image Medley software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_SII $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID endmenu diff -urN linux-2.4.25/drivers/ide/Makefile linux-2.4.26/drivers/ide/Makefile --- linux-2.4.25/drivers/ide/Makefile 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/ide/Makefile 2004-04-14 06:05:29.000000000 -0700 @@ -28,9 +28,13 @@ # Core IDE code - must come before legacy -ide-core-objs := ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o ide-default.o ide-proc.o ide-probe.o ide-geometry.o +ide-core-objs := ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o \ + ide-default.o ide-probe.o ide-geometry.o ide-detect-objs := ide-probe-mini.o +ifeq ($(CONFIG_PROC_FS),y) +ide-core-objs += ide-proc.o +endif ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) ide-core-objs += setup-pci.o endif diff -urN linux-2.4.25/drivers/ide/ide-probe.c linux-2.4.26/drivers/ide/ide-probe.c --- linux-2.4.25/drivers/ide/ide-probe.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/ide/ide-probe.c 2004-04-14 06:05:29.000000000 -0700 @@ -102,7 +102,8 @@ if (id->config == 0x848a) return 1; /* CompactFlash */ if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */ || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */ - || !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */ + || !strncmp(id->model, "SunDisk SDCFB", 13) /* old SanDisk */ + || !strncmp(id->model, "SanDisk SDCFB", 13) /* SanDisk */ || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */ || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */ || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */ diff -urN linux-2.4.25/drivers/ide/ide-proc.c linux-2.4.26/drivers/ide/ide-proc.c --- linux-2.4.25/drivers/ide/ide-proc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/ide/ide-proc.c 2004-04-14 06:05:29.000000000 -0700 @@ -811,35 +811,6 @@ EXPORT_SYMBOL(create_proc_ide_drives); -void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct proc_dir_entry *ent; - struct proc_dir_entry *parent = hwif->proc; - char name[64]; -// ide_driver_t *driver = drive->driver; - - if (drive->present && !drive->proc) { - drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - -/* - * assume that we have these already, however, should test FIXME! - * if (driver) { - * ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - * ide_add_proc_entries(drive->proc, driver->proc, drive); - * } - * - */ - sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); - ent = proc_symlink(drive->name, proc_ide_root, name); - if (!ent) - return; - } -} - -EXPORT_SYMBOL(recreate_proc_ide_device); - void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) { ide_driver_t *driver = drive->driver; diff -urN linux-2.4.25/drivers/ide/pci/Makefile linux-2.4.26/drivers/ide/pci/Makefile --- linux-2.4.25/drivers/ide/pci/Makefile 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/ide/pci/Makefile 2004-04-14 06:05:29.000000000 -0700 @@ -8,6 +8,7 @@ obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o +obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o diff -urN linux-2.4.25/drivers/ide/pci/amd74xx.c linux-2.4.26/drivers/ide/pci/amd74xx.c --- linux-2.4.25/drivers/ide/pci/amd74xx.c 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.26/drivers/ide/pci/amd74xx.c 2004-04-14 06:05:29.000000000 -0700 @@ -1,7 +1,7 @@ /* - * Version 2.10 + * Version 2.13 * - * AMD 755/756/766/8111 and nVidia nForce IDE driver for Linux. + * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s IDE driver for Linux. * * Copyright (c) 2000-2002 Vojtech Pavlik * @@ -40,9 +40,11 @@ #define AMD_UDMA_33 0x01 #define AMD_UDMA_66 0x02 #define AMD_UDMA_100 0x03 +#define AMD_UDMA_133 0x04 #define AMD_CHECK_SWDMA 0x08 #define AMD_BAD_SWDMA 0x10 #define AMD_BAD_FIFO 0x20 +#define AMD_CHECK_SERENADE 0x40 /* * AMD SouthBridge chips. @@ -50,29 +52,32 @@ static struct amd_ide_chip { unsigned short id; - unsigned char rev; unsigned long base; unsigned char flags; } amd_ide_chips[] = { - { PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA }, /* AMD-755 Cobra */ - { PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA }, /* AMD-756 Viper */ - { PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO }, /* AMD-766 Viper */ - { PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-768 Opus */ - { PCI_DEVICE_ID_AMD_8111_IDE, 0x00, 0x40, AMD_UDMA_100 }, /* AMD-8111 */ - { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 }, /* nVidia nForce */ - { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x00, 0x50, AMD_UDMA_100 }, /* nVidia nForce */ - + { PCI_DEVICE_ID_AMD_COBRA_7401, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA }, + { PCI_DEVICE_ID_AMD_VIPER_7409, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA }, + { PCI_DEVICE_ID_AMD_VIPER_7411, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO }, + { PCI_DEVICE_ID_AMD_OPUS_7441, 0x40, AMD_UDMA_100 }, + { PCI_DEVICE_ID_AMD_8111_IDE, 0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE }, + { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x50, AMD_UDMA_100 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { 0 } }; static struct amd_ide_chip *amd_config; -static unsigned char amd_enabled; +static ide_pci_device_t *amd_chipset; static unsigned int amd_80w; static unsigned int amd_clock; -static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3 }; -static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 1 }; -static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" }; +static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" }; +static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 }; /* * AMD /proc entry. @@ -83,6 +88,7 @@ #include #include +static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 }; static unsigned long amd_base; static struct pci_dev *bmide_dev; extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ @@ -104,7 +110,7 @@ amd_print("----------AMD BusMastering IDE Configuration----------------"); - amd_print("Driver Version: 2.10"); + amd_print("Driver Version: 2.13"); amd_print("South Bridge: %s", bmide_dev->name); pci_read_config_byte(dev, PCI_REVISION_ID, &t); @@ -155,6 +161,12 @@ continue; } + if (den[i] && uen[i] && udma[i] == 15) { + speed[i] = amd_clock * 4; + cycle[i] = 500000 / amd_clock; + continue; + } + speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2); cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2; } @@ -200,6 +212,7 @@ case AMD_UDMA_33: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; case AMD_UDMA_66: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break; case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break; + case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break; default: return; } @@ -234,6 +247,7 @@ } if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1; + if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t); @@ -251,9 +265,6 @@ static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio) { - if (!((amd_enabled >> HWIF(drive)->channel) & 1)) - return; - if (pio == 255) { amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO)); return; @@ -276,7 +287,8 @@ XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) | (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) | - (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0)); + (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) | + (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0)); amd_set_drive(drive, speed); @@ -312,13 +324,15 @@ switch (amd_config->flags & AMD_UDMA) { + case AMD_UDMA_133: case AMD_UDMA_100: pci_read_config_byte(dev, AMD_CABLE_DETECT, &t); pci_read_config_dword(dev, AMD_UDMA_TIMING, &u); amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); for (i = 24; i >= 0; i -= 8) if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n"); + printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n", + amd_chipset->name); amd_80w |= (1 << (1 - (i >> 4))); } break; @@ -331,9 +345,6 @@ break; } - pci_read_config_dword(dev, AMD_IDE_ENABLE, &u); - amd_enabled = ((u & 1) ? 2 : 0) | ((u & 2) ? 1 : 0); - /* * Take care of prefetch & postwrite. */ @@ -343,6 +354,15 @@ (amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0)); /* + * Take care of incorrectly wired Serenade mainboards. + */ + + if ((amd_config->flags & AMD_CHECK_SERENADE) && + dev->subsystem_vendor == PCI_VENDOR_ID_AMD && + dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) + amd_config->flags = AMD_UDMA_100; + +/* * Determine the system bus clock. */ @@ -355,8 +375,10 @@ } if (amd_clock < 20000 || amd_clock > 50000) { - printk(KERN_WARNING "AMD_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", amd_clock); - printk(KERN_WARNING "AMD_IDE: Use ide0=ata66 if you want to assume 80-wire cable\n"); + printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", + amd_chipset->name, amd_clock); + printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n", + amd_chipset->name); amd_clock = 33333; } @@ -365,8 +387,8 @@ */ pci_read_config_byte(dev, PCI_REVISION_ID, &t); - printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n", - dev->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name); + printk(KERN_INFO "%s: %s (rev %02x) %s controller\n", + amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]); /* * Register /proc/ide/amd74xx entry @@ -381,13 +403,7 @@ } #endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */ - - return 0; -} - -static unsigned int __init ata66_amd74xx(ide_hwif_t *hwif) -{ - return ((amd_enabled & amd_80w) >> hwif->channel) & 1; + return dev->irq; } static void __init init_hwif_amd74xx(ide_hwif_t *hwif) @@ -414,8 +430,8 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; - if (!(hwif->udma_four)) - hwif->udma_four = ((amd_enabled & amd_80w) >> hwif->channel) & 1; + if (!hwif->udma_four) + hwif->udma_four = (amd_80w >> hwif->channel) & 1; hwif->ide_dma_check = &amd74xx_ide_dma_check; if (!noautodma) hwif->autodma = 1; @@ -423,37 +439,31 @@ hwif->drives[1].autodma = hwif->autodma; } -/* - * We allow the BM-DMA driver only work on enabled interfaces. - */ - -static void __init init_dma_amd74xx(ide_hwif_t *hwif, unsigned long dmabase) -{ - if ((amd_enabled >> hwif->channel) & 1) - ide_setup_dma(hwif, dmabase, 8); -} - -extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *); - static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) { - ide_pci_device_t *d = amd74xx_chipsets + id->driver_data; + amd_chipset = amd74xx_chipsets + id->driver_data; amd_config = amd_ide_chips + id->driver_data; - if (dev->device != d->device) BUG(); + if (dev->device != amd_chipset->device) BUG(); if (dev->device != amd_config->id) BUG(); - ide_setup_pci_device(dev, d); + ide_setup_pci_device(dev, amd_chipset); MOD_INC_USE_COUNT; return 0; } static struct pci_device_id amd74xx_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, { 0, }, }; diff -urN linux-2.4.25/drivers/ide/pci/amd74xx.h linux-2.4.26/drivers/ide/pci/amd74xx.h --- linux-2.4.25/drivers/ide/pci/amd74xx.h 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.26/drivers/ide/pci/amd74xx.h 2004-04-14 06:05:29.000000000 -0700 @@ -27,7 +27,6 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *); static void init_hwif_amd74xx(ide_hwif_t *); -static void init_dma_amd74xx(ide_hwif_t *, unsigned long); static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { { /* 0 */ @@ -35,9 +34,7 @@ .device = PCI_DEVICE_ID_AMD_COBRA_7401, .name = "AMD7401", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, @@ -48,9 +45,7 @@ .device = PCI_DEVICE_ID_AMD_VIPER_7409, .name = "AMD7409", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, @@ -61,9 +56,7 @@ .device = PCI_DEVICE_ID_AMD_VIPER_7411, .name = "AMD7411", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, @@ -74,9 +67,7 @@ .device = PCI_DEVICE_ID_AMD_OPUS_7441, .name = "AMD7441", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, @@ -87,9 +78,7 @@ .device = PCI_DEVICE_ID_AMD_8111_IDE, .name = "AMD8111", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .autodma = AUTODMA, .channels = 2, .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, @@ -101,9 +90,7 @@ .device = PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, .name = "NFORCE", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, @@ -115,15 +102,79 @@ .device = PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, .name = "NFORCE2", .init_chipset = init_chipset_amd74xx, - .init_iops = NULL, .init_hwif = init_hwif_amd74xx, - .init_dma = init_dma_amd74xx, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, .bootable = ON_BOARD, .extra = 0, }, + { /* 7 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, + .name = "NFORCE2S", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, + { /* 8 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, + .name = "NFORCE2S-SATA", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, + { /* 9 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, + .name = "NFORCE3", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, + { /* 10 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, + .name = "NFORCE3S", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, + { /* 11 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, + .name = "NFORCE3S-SATA", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, + { /* 12 */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, + .name = "NFORCE3S-SATA2", + .init_chipset = init_chipset_amd74xx, + .init_hwif = init_hwif_amd74xx, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, + .bootable = ON_BOARD, + }, { .vendor = 0, .device = 0, diff -urN linux-2.4.25/drivers/ide/pci/atiixp.c linux-2.4.26/drivers/ide/pci/atiixp.c --- linux-2.4.25/drivers/ide/pci/atiixp.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/ide/pci/atiixp.c 2004-04-14 06:05:29.000000000 -0700 @@ -0,0 +1,522 @@ +/* + * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004 + * + * Copyright (C) 2003 ATI Inc. + * Copyright (C) 2004 Bartlomiej Zolnierkiewicz + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ide_modes.h" + +#define ATIIXP_IDE_PIO_TIMING 0x40 +#define ATIIXP_IDE_MDMA_TIMING 0x44 +#define ATIIXP_IDE_PIO_CONTROL 0x48 +#define ATIIXP_IDE_PIO_MODE 0x4a +#define ATIIXP_IDE_UDMA_CONTROL 0x54 +#define ATIIXP_IDE_UDMA_MODE 0x56 + +typedef struct { + u8 command_width; + u8 recover_width; +} atiixp_ide_timing; + +static atiixp_ide_timing pio_timing[] = { + { 0x05, 0x0d }, + { 0x04, 0x07 }, + { 0x03, 0x04 }, + { 0x02, 0x02 }, + { 0x02, 0x00 }, +}; + +static atiixp_ide_timing mdma_timing[] = { + { 0x07, 0x07 }, + { 0x02, 0x01 }, + { 0x02, 0x00 }, +}; + +static int save_mdma_mode[4]; + +#define DISPLAY_ATIIXP_TIMINGS + +#if defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS) + +#include +#include + +static u8 atiixp_proc; +static struct pci_dev *bmide_dev; + +/** + * atiixp_get_info - fill in /proc for ATIIXP IDE + * @buffer: buffer to fill + * @addr: address of user start in buffer + * @offset: offset into 'file' + * @count: buffer count + * + * Output summary data on the tuning. + */ + +static int atiixp_get_info(char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + struct pci_dev *dev = bmide_dev; + unsigned long bibma = pci_resource_start(dev, 4); + u32 mdma_timing = 0; + u16 udma_mode = 0, pio_mode = 0; + u8 c0, c1, udma_control = 0; + + p += sprintf(p, "\n ATI "); + p += sprintf(p, "ATIIXP Ultra100 IDE Chipset.\n"); + + pci_read_config_byte(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_control); + pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &udma_mode); + pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode); + pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &mdma_timing); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb(bibma + 0x02); + c1 = inb(bibma + 0x0a); + + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", + (c0 & 0x80) ? "dis" : " en", + (c1 & 0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 " + "-------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s " + " %s %s\n", + (c0 & 0x20) ? "yes" : "no ", + (c0 & 0x40) ? "yes" : "no ", + (c1 & 0x20) ? "yes" : "no ", + (c1 & 0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s " + " %s %s\n", + (udma_control & 0x01) ? "yes" : "no ", + (udma_control & 0x02) ? "yes" : "no ", + (udma_control & 0x04) ? "yes" : "no ", + (udma_control & 0x08) ? "yes" : "no " ); + p += sprintf(p, "UDMA mode: %c %c " + " %c %c\n", + (udma_control & 0x01) ? + ((udma_mode & 0x07) + 48) : 'X', + (udma_control & 0x02) ? + (((udma_mode >> 4) & 0x07) + 48) : 'X', + (udma_control & 0x04) ? + (((udma_mode >> 8) & 0x07) + 48) : 'X', + (udma_control & 0x08) ? + (((udma_mode >> 12) & 0x07) + 48) : 'X'); + p += sprintf(p, "MDMA mode: %c %c " + " %c %c\n", + (save_mdma_mode[0] && (c0 & 0x20)) ? + ((save_mdma_mode[0] & 0xf) + 48) : 'X', + (save_mdma_mode[1] && (c0 & 0x40)) ? + ((save_mdma_mode[1] & 0xf) + 48) : 'X', + (save_mdma_mode[2] && (c1 & 0x20)) ? + ((save_mdma_mode[2] & 0xf) + 48) : 'X', + (save_mdma_mode[3] && (c1 & 0x40)) ? + ((save_mdma_mode[3] & 0xf) + 48) : 'X'); + p += sprintf(p, "PIO mode: %c %c " + " %c %c\n", + (c0 & 0x20) ? 'X' : ((pio_mode & 0x07) + 48), + (c0 & 0x40) ? 'X' : (((pio_mode >> 4) & 0x07) + 48), + (c1 & 0x20) ? 'X' : (((pio_mode >> 8) & 0x07) + 48), + (c1 & 0x40) ? 'X' : (((pio_mode >> 12) & 0x07) + 48)); + + return p - buffer; /* => must be less than 4k! */ +} + +static ide_pci_host_proc_t atiixp_procs = { + .name = "atiixp", + .set = 1, + .get_info = atiixp_get_info, +}; +#endif /* defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS) */ + +/** + * atiixp_ratemask - compute rate mask for ATIIXP IDE + * @drive: IDE drive to compute for + * + * Returns the available modes for the ATIIXP IDE controller. + */ + +static u8 atiixp_ratemask(ide_drive_t *drive) +{ + u8 mode = 3; + + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * atiixp_dma_2_pio - return the PIO mode matching DMA + * @xfer_rate: transfer speed + * + * Returns the nearest equivalent PIO timing for the PIO or DMA + * mode requested by the controller. + */ + +static u8 atiixp_dma_2_pio(u8 xfer_rate) { + switch(xfer_rate) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_PIO_4: + return 4; + case XFER_MW_DMA_1: + case XFER_PIO_3: + return 3; + case XFER_SW_DMA_2: + case XFER_PIO_2: + return 2; + case XFER_MW_DMA_0: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + case XFER_PIO_1: + case XFER_PIO_0: + case XFER_PIO_SLOW: + default: + return 0; + } +} + +static int atiixp_ide_dma_host_on(ide_drive_t *drive) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + unsigned long flags; + u16 tmp16; + + spin_lock_irqsave(&ide_lock, flags); + + pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); + if (save_mdma_mode[drive->dn]) + tmp16 &= ~(1 << drive->dn); + else + tmp16 |= (1 << drive->dn); + pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); + + spin_unlock_irqrestore(&ide_lock, flags); + + return __ide_dma_host_on(drive); +} + +static int atiixp_ide_dma_host_off(ide_drive_t *drive) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + unsigned long flags; + u16 tmp16; + + spin_lock_irqsave(&ide_lock, flags); + + pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); + tmp16 &= ~(1 << drive->dn); + pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); + + spin_unlock_irqrestore(&ide_lock, flags); + + return __ide_dma_host_off(drive); +} + +/** + * atiixp_tune_drive - tune a drive attached to a ATIIXP + * @drive: drive to tune + * @pio: desired PIO mode + * + * Set the interface PIO mode. + */ + +static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + unsigned long flags; + int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; + u32 pio_timing_data; + u16 pio_mode_data; + + spin_lock_irqsave(&ide_lock, flags); + + pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); + pio_mode_data &= ~(0x07 << (drive->dn * 4)); + pio_mode_data |= (pio << (drive->dn * 4)); + pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data); + + pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); + pio_timing_data &= ~(0xff << timing_shift); + pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) | + (pio_timing[pio].command_width << (timing_shift + 4)); + pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); + + spin_unlock_irqrestore(&ide_lock, flags); +} + +/** + * atiixp_tune_chipset - tune a ATIIXP interface + * @drive: IDE drive to tune + * @xferspeed: speed to configure + * + * Set a ATIIXP interface channel to the desired speeds. This involves + * requires the right timing data into the ATIIXP configuration space + * then setting the drive parameters appropriately + */ + +static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + unsigned long flags; + int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; + u32 tmp32; + u16 tmp16; + u8 speed, pio; + + speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed); + + spin_lock_irqsave(&ide_lock, flags); + + save_mdma_mode[drive->dn] = 0; + if (speed >= XFER_UDMA_0) { + pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16); + tmp16 &= ~(0x07 << (drive->dn * 4)); + tmp16 |= ((speed & 0x07) << (drive->dn * 4)); + pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16); + } else { + if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) { + save_mdma_mode[drive->dn] = speed; + pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); + tmp32 &= ~(0xff << timing_shift); + tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) | + (mdma_timing[speed & 0x03].command_width << (timing_shift + 4)); + pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); + } + } + + spin_unlock_irqrestore(&ide_lock, flags); + + if (speed >= XFER_SW_DMA_0) + pio = atiixp_dma_2_pio(speed); + else + pio = speed - XFER_PIO_0; + + atiixp_tuneproc(drive, pio); + + return ide_config_drive_speed(drive, speed); +} + +/** + * atiixp_config_drive_for_dma - configure drive for DMA + * @drive: IDE drive to configure + * + * Set up a ATIIXP interface channel for the best available speed. + * We prefer UDMA if it is available and then MWDMA. If DMA is + * not available we switch to PIO and return 0. + */ + +static int atiixp_config_drive_for_dma(ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive)); + + /* If no DMA speed was available then disable DMA and use PIO. */ + if (!speed) { + u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; + } + + (void) atiixp_speedproc(drive, speed); + return ide_dma_enable(drive); +} + +/** + * atiixp_dma_check - set up an IDE device + * @drive: IDE drive to configure + * + * Set up the ATIIXP interface for the best available speed on this + * interface, preferring DMA to PIO. + */ + +static int atiixp_dma_check(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; + u8 tspeed, speed; + + drive->init_speed = 0; + + if ((id->capability & 1) && drive->autodma) { + /* Consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + goto fast_ata_pio; + if (id->field_valid & 4) { + if (id->dma_ultra & hwif->ultra_mask) { + /* Force if Capable UltraDMA */ + if ((id->field_valid & 2) && + (!atiixp_config_drive_for_dma(drive))) + goto try_dma_modes; + } + } else if (id->field_valid & 2) { +try_dma_modes: + if ((id->dma_mword & hwif->mwdma_mask) || + (id->dma_1word & hwif->swdma_mask)) { + /* Force if Capable regular DMA modes */ + if (!atiixp_config_drive_for_dma(drive)) + goto no_dma_set; + } + } else if (__ide_dma_good_drive(drive) && + (id->eide_dma_time < 150)) { + /* Consult the list of known "good" drives */ + if (!atiixp_config_drive_for_dma(drive)) + goto no_dma_set; + } else { + goto fast_ata_pio; + } + return hwif->ide_dma_on(drive); + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: +no_dma_set: + tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); + speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; + hwif->speedproc(drive, speed); + return hwif->ide_dma_off_quietly(drive); + } + /* IORDY not supported */ + return 0; +} + +/** + * init_chipset_atiixp - set up the ATIIXP chipset + * @dev: PCI device to set up + * @name: Name of the device + * + * Initialize the PCI device as required. For the ATIIXP this turns + * out to be nice and simple + */ + +static unsigned int __devinit init_chipset_atiixp(struct pci_dev *dev, const char *name) +{ +#if defined(DISPLAY_ATIIXP_TIMINGS) && defined(CONFIG_PROC_FS) + if (!atiixp_proc) { + atiixp_proc = 1; + bmide_dev = dev; + ide_pci_register_host_proc(&atiixp_procs); + } +#endif /* DISPLAY_ATIIXP_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +/** + * init_hwif_atiixp - fill in the hwif for the ATIIXP + * @hwif: IDE interface + * + * Set up the ide_hwif_t for the ATIIXP interface according to the + * capabilities of the hardware. + */ + +static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) +{ + if (!hwif->irq) + hwif->irq = hwif->channel ? 15 : 14; + + hwif->autodma = 0; + hwif->tuneproc = &atiixp_tuneproc; + hwif->speedproc = &atiixp_speedproc; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x3f; + hwif->mwdma_mask = 0x06; + hwif->swdma_mask = 0x04; + + /* FIXME: proper cable detection needed */ + hwif->udma_four = 1; + hwif->ide_dma_host_on = &atiixp_ide_dma_host_on; + hwif->ide_dma_host_off = &atiixp_ide_dma_host_off; + hwif->ide_dma_check = &atiixp_dma_check; + if (!noautodma) + hwif->autodma = 1; + + hwif->drives[1].autodma = hwif->autodma; + hwif->drives[0].autodma = hwif->autodma; +} + +static ide_pci_device_t atiixp_pci_info[] __devinitdata = { + { /* 0 */ + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_IXP_IDE, + .name = "ATIIXP", + .init_chipset = init_chipset_atiixp, + .init_hwif = init_hwif_atiixp, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, + .bootable = ON_BOARD, + } +}; + +/** + * atiixp_init_one - called when a ATIIXP is found + * @dev: the atiixp device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_pci_device_t *d = &atiixp_pci_info[id->driver_data]; + + if (dev->device != d->device) + BUG(); + ide_setup_pci_device(dev, d); + return 0; +} + +static struct pci_device_id atiixp_pci_tbl[] = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +static struct pci_driver driver = { + .name = "ATIIXP IDE", + .id_table = atiixp_pci_tbl, + .probe = atiixp_init_one, +}; + +static int atiixp_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(atiixp_ide_init); + +MODULE_AUTHOR("HUI YU"); +MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE"); +MODULE_LICENSE("GPL"); + +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.25/drivers/ide/pci/generic.h linux-2.4.26/drivers/ide/pci/generic.h --- linux-2.4.25/drivers/ide/pci/generic.h 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.26/drivers/ide/pci/generic.h 2004-04-14 06:05:29.000000000 -0700 @@ -148,6 +148,7 @@ } }; +#if 0 static ide_pci_device_t unknown_chipset[] __devinitdata = { { /* 0 */ .vendor = 0, @@ -170,5 +171,6 @@ } }; +#endif #endif /* IDE_GENERIC_H */ diff -urN linux-2.4.25/drivers/ide/pci/hpt366.c linux-2.4.26/drivers/ide/pci/hpt366.c --- linux-2.4.25/drivers/ide/pci/hpt366.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.26/drivers/ide/pci/hpt366.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /* * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 * - * Copyright (C) 1999-2002 Andre Hedrick + * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. * Portions Copyright (C) 2003 Red Hat Inc * @@ -668,6 +668,31 @@ return __ide_dma_lostirq(drive); } +/* returns 1 if DMA IRQ issued, 0 otherwise */ +static int hpt374_ide_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u16 bfifo = 0; + u8 reginfo = hwif->channel ? 0x56 : 0x52; + u8 dma_stat; + + pci_read_config_word(hwif->pci_dev, reginfo, &bfifo); + if (bfifo & 0x1FF) { +// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); + return 0; + } + + dma_stat = hwif->INB(hwif->dma_status); + /* return 1 if INTR asserted */ + if ((dma_stat & 4) == 4) + return 1; + + if (!drive->waiting_for_dma) + printk(KERN_WARNING "%s: (%s) called while not waiting\n", + drive->name, __FUNCTION__); + return 0; +} + static int hpt374_ide_dma_end (ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; @@ -1245,11 +1270,13 @@ hwif->udma_four = ((ata66 & regmask) ? 0 : 1); hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; - if (hpt_minimum_revision(dev,8)) + if (hpt_minimum_revision(dev,8)) { + hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; hwif->ide_dma_end = &hpt374_ide_dma_end; - else if (hpt_minimum_revision(dev,5)) + } else if (hpt_minimum_revision(dev,5)) { + hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; hwif->ide_dma_end = &hpt374_ide_dma_end; - else if (hpt_minimum_revision(dev,3)) { + } else if (hpt_minimum_revision(dev,3)) { hwif->ide_dma_begin = &hpt370_ide_dma_begin; hwif->ide_dma_end = &hpt370_ide_dma_end; hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; diff -urN linux-2.4.25/drivers/ide/pci/piix.c linux-2.4.26/drivers/ide/pci/piix.c --- linux-2.4.25/drivers/ide/pci/piix.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/ide/pci/piix.c 2004-04-14 06:05:30.000000000 -0700 @@ -153,6 +153,8 @@ case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_ESB_2: + case PCI_DEVICE_ID_INTEL_ICH6_2: p += sprintf(p, "PIIX4 Ultra 100 "); break; case PCI_DEVICE_ID_INTEL_82372FB_1: @@ -290,6 +292,8 @@ case PCI_DEVICE_ID_INTEL_82801DB_10: case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: + case PCI_DEVICE_ID_INTEL_ESB_2: + case PCI_DEVICE_ID_INTEL_ICH6_2: mode = 3; break; /* UDMA 66 capable */ @@ -680,6 +684,8 @@ case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_ESB_2: + case PCI_DEVICE_ID_INTEL_ICH6_2: { unsigned int extra = 0; pci_read_config_dword(dev, 0x54, &extra); @@ -875,6 +881,8 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, { 0, }, }; diff -urN linux-2.4.25/drivers/ide/pci/piix.h linux-2.4.26/drivers/ide/pci/piix.h --- linux-2.4.25/drivers/ide/pci/piix.h 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.26/drivers/ide/pci/piix.h 2004-04-14 06:05:30.000000000 -0700 @@ -305,6 +305,34 @@ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 19 */ + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_ESB_2, + .name = "ICH5", + .init_setup = init_setup_piix, + .init_chipset = init_chipset_piix, + .init_iops = NULL, + .init_hwif = init_hwif_piix, + .init_dma = init_dma_piix, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, + .bootable = ON_BOARD, + .extra = 0, + },{ /* 20 */ + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_ICH6_2, + .name = "ICH6", + .init_setup = init_setup_piix, + .init_chipset = init_chipset_piix, + .init_iops = NULL, + .init_hwif = init_hwif_piix, + .init_dma = init_dma_piix, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, + .bootable = ON_BOARD, + .extra = 0, },{ .vendor = 0, .device = 0, diff -urN linux-2.4.25/drivers/ide/pci/siimage.c linux-2.4.26/drivers/ide/pci/siimage.c --- linux-2.4.25/drivers/ide/pci/siimage.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/ide/pci/siimage.c 2004-04-14 06:05:30.000000000 -0700 @@ -62,6 +62,7 @@ return 0; } BUG(); + return 0; } /** diff -urN linux-2.4.25/drivers/ide/raid/Makefile linux-2.4.26/drivers/ide/raid/Makefile --- linux-2.4.25/drivers/ide/raid/Makefile 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.26/drivers/ide/raid/Makefile 2004-04-14 06:05:30.000000000 -0700 @@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_ATARAID) += ataraid.o obj-$(CONFIG_BLK_DEV_ATARAID_PDC) += pdcraid.o obj-$(CONFIG_BLK_DEV_ATARAID_HPT) += hptraid.o +obj-$(CONFIG_BLK_DEV_ATARAID_MEDLEY) += medley.o obj-$(CONFIG_BLK_DEV_ATARAID_SII) += silraid.o EXTRA_CFLAGS := -I../ diff -urN linux-2.4.25/drivers/ide/raid/medley.c linux-2.4.26/drivers/ide/raid/medley.c --- linux-2.4.25/drivers/ide/raid/medley.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/ide/raid/medley.c 2004-04-14 06:05:30.000000000 -0700 @@ -0,0 +1,752 @@ +/* + * MEDLEY SOFTWARE RAID DRIVER (Silicon Image 3112 and others) + * + * Copyright (C) 2003 Thomas Horsten + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Copyright (C) 2003 Thomas Horsten + * All Rights Reserved. + * + * This driver uses the ATA RAID driver framework and is based on + * code from Arjan van de Ven's silraid.c and hptraid.c. + * + * It is a driver for the Medley software RAID, which is used by + * some IDE controllers, including the Silicon Image 3112 SATA + * controller found onboard many modern motherboards, and the + * CMD680 stand-alone PCI RAID controller. + * + * The author has only tested this on the Silicon Image SiI3112. + * If you have any luck using more than 2 drives, and/or more + * than one RAID set, and/or any other chip than the SiI3112, + * please let me know by sending me mail at the above address. + * + * Currently, only striped mode is supported for these RAIDs. + * + * You are welcome to contact me if you have any questions or + * suggestions for improvement. + * + * Change history: + * + * 20040310 - thomas@horsten.com + * Removed C99 style variable declarations that confused gcc-2.x + * Fixed a bug where more than one RAID set would not be detected correctly + * General cleanup for submission to kernel + * + * 20031012 - thomas@horsten.com + * Added support for BLKRRPART ioctl to re-read partition table + * + * 20030801 - thomas@horsten.com + * First test release + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ataraid.h" + +/* + * These options can be tuned if the need should occur. + * + * Even better, this driver could be changed to allocate the structures + * dynamically. + */ +#define MAX_DRIVES_PER_SET 8 +#define MAX_MEDLEY_ARRAYS 4 + +/* + * Set to 1 only if you are debugging the driver, or if it doesn't work + * the way you expect and you want to to report it. + * + * This will produce lots of kernel messages, some of which might + * help me figure out what is going wrong). + */ +#define DEBUGGING_MEDLEY 0 + +#if DEBUGGING_MEDLEY +#define dprintk(fmt, args...) printk(fmt, ##args) +#else +#define dprintk(fmt, args...) +#endif + +/* + * Medley RAID metadata structure. + * + * The metadata structure is based on the ATA drive ID from the drive itself, + * with the RAID information in the vendor specific regions. + * + * We do not use all the fields, since we only support Striped Sets. + */ +struct medley_metadata { + u8 driveid0[46]; + u8 ascii_version[8]; + u8 driveid1[52]; + u32 total_sectors_low; + u32 total_sectors_high; + u16 reserved0; + u8 driveid2[142]; + u16 product_id; + u16 vendor_id; + u16 minor_ver; + u16 major_ver; + u16 creation_timestamp[3]; + u16 chunk_size; + u16 reserved1; + u8 drive_number; + u8 raid_type; + u8 drives_per_striped_set; + u8 striped_set_number; + u8 drives_per_mirrored_set; + u8 mirrored_set_number; + u32 rebuild_ptr_low; + u32 rebuild_ptr_high; + u32 incarnation_no; + u8 member_status; + u8 mirrored_set_state; + u8 reported_device_location; + u8 member_location; + u8 auto_rebuild; + u8 reserved3[17]; + u16 checksum; +}; + +/* + * This struct holds the information about a Medley array + */ +struct medley_array { + u8 drives; + u16 chunk_size; + u32 sectors_per_row; + u8 chunk_size_log; + u16 present; + u16 timestamp[3]; + u32 sectors; + int registered; + atomic_t valid; + int access; + + kdev_t members[MAX_DRIVES_PER_SET]; + struct block_device *bdev[MAX_DRIVES_PER_SET]; +}; + +static struct medley_array raid[MAX_MEDLEY_ARRAYS]; + +/* + * Here we keep the offset of the ATARAID device ID's compared to our + * own (this will normally be 0, unless another ATARAID driver has + * registered some arrays before us). + */ +static int medley_devid_offset = 0; + +/* + * This holds the number of detected arrays. + */ +static int medley_arrays = 0; + +/* + * Wait queue for opening device (used when re-reading partition table) + */ +static DECLARE_WAIT_QUEUE_HEAD(medley_wait_open); + +/* + * The interface functions used by the ataraid framework. + */ +static int medley_open(struct inode *inode, struct file *filp); +static int medley_release(struct inode *inode, struct file *filp); +static int medley_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int medley_make_request(request_queue_t * q, int rw, + struct buffer_head *bh); + +static struct raid_device_operations medley_ops = { + open: medley_open, + release: medley_release, + ioctl: medley_ioctl, + make_request: medley_make_request +}; + +/* + * This is the list of devices to probe. + */ +static const kdev_t probelist[] = { + MKDEV(IDE0_MAJOR, 0), + MKDEV(IDE0_MAJOR, 64), + MKDEV(IDE1_MAJOR, 0), + MKDEV(IDE1_MAJOR, 64), + MKDEV(IDE2_MAJOR, 0), + MKDEV(IDE2_MAJOR, 64), + MKDEV(IDE3_MAJOR, 0), + MKDEV(IDE3_MAJOR, 64), + MKDEV(IDE4_MAJOR, 0), + MKDEV(IDE4_MAJOR, 64), + MKDEV(IDE5_MAJOR, 0), + MKDEV(IDE5_MAJOR, 64), + MKDEV(IDE6_MAJOR, 0), + MKDEV(IDE6_MAJOR, 64), + MKDEV(0, 0) +}; + +/* + * Handler for ioctl calls to the virtual device + */ +static int medley_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor; + unsigned long sectors; + int devminor = (inode->i_rdev >> SHIFT) & MAJOR_MASK; + int device = devminor - medley_devid_offset; + int partition; + + dprintk("medley_ioctl\n"); + + minor = MINOR(inode->i_rdev) >> SHIFT; + + switch (cmd) { + + case BLKGETSIZE: /* Return device size */ + if (!arg) + return -EINVAL; + sectors = + ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects; + dprintk("medley_ioctl: BLKGETSIZE\n"); + if (MINOR(inode->i_rdev) & 15) + return put_user(sectors, (unsigned long *) arg); + return put_user(raid[minor - medley_devid_offset].sectors, + (unsigned long *) arg); + break; + + case HDIO_GETGEO: { + struct hd_geometry *loc = + (struct hd_geometry *) arg; + unsigned short bios_cyl = (unsigned short) + (raid[minor].sectors / 255 / 63); /* truncate */ + + dprintk("medley_ioctl: HDIO_GETGEO\n"); + if (!loc) + return -EINVAL; + if (put_user(255, (byte *) & loc->heads)) + return -EFAULT; + if (put_user(63, (byte *) & loc->sectors)) + return -EFAULT; + if (put_user + (bios_cyl, (unsigned short *) &loc->cylinders)) + return -EFAULT; + if (put_user + ((unsigned) ataraid_gendisk. + part[MINOR(inode->i_rdev)].start_sect, + (unsigned long *) &loc->start)) + return -EFAULT; + return 0; + } + + case HDIO_GETGEO_BIG: { + struct hd_big_geometry *loc = + (struct hd_big_geometry *) arg; + + dprintk("medley_ioctl: HDIO_GETGEO_BIG\n"); + if (!loc) + return -EINVAL; + if (put_user(255, (byte *) & loc->heads)) + return -EFAULT; + if (put_user(63, (byte *) & loc->sectors)) + return -EFAULT; + if (put_user + (raid[minor - medley_devid_offset].sectors / + 255 / 63, (unsigned int *) &loc->cylinders)) + return -EFAULT; + if (put_user + ((unsigned) ataraid_gendisk. + part[MINOR(inode->i_rdev)].start_sect, + (unsigned long *) &loc->start)) + return -EFAULT; + return 0; + } + + case BLKROSET: + case BLKROGET: + case BLKSSZGET: + dprintk("medley_ioctl: BLK*\n"); + return blk_ioctl(inode->i_rdev, cmd, arg); + + case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (minor != 0) + return -EINVAL; + if (atomic_read(&(raid[device].valid)) == 0) + return -EINVAL; + + atomic_set(&(raid[device].valid), 0); + if (raid[device].access != 1) { + atomic_set(&(raid[device].valid), 1); + return -EBUSY; + } + + for (partition = 15; partition >= 0; partition--) { + invalidate_device(MKDEV(ATARAID_MAJOR, + partition + devminor), 1); + ataraid_gendisk.part[partition + + devminor].start_sect = 0; + ataraid_gendisk.part[partition + + devminor].nr_sects = 0; + } + ataraid_register_disk(device, raid[device].sectors); + atomic_set(&(raid[device].valid), 1); + wake_up(&medley_wait_open); + return 0; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Handler to map a request to the real device. + * If the request cannot be made because it spans multiple disks, + * we return -1, otherwise we modify the request and return 1. + */ +static int medley_make_request(request_queue_t * q, int rw, + struct buffer_head *bh) +{ + u8 disk; + u32 rsect = bh->b_rsector; + int device = + ((bh->b_rdev >> SHIFT) & MAJOR_MASK) - medley_devid_offset; + struct medley_array *r = raid + device; + + /* Add the partition offset */ + rsect = rsect + ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; + + dprintk("medley_make_request, rsect=%ul\n", rsect); + + /* Detect if the request crosses a chunk barrier */ + if (r->chunk_size_log) { + if (((rsect & (r->chunk_size - 1)) + + (bh->b_size / 512)) > (1 << r->chunk_size_log)) { + return -1; + } + } else { + if ((rsect / r->chunk_size) != + ((rsect + (bh->b_size / 512) - 1) / r->chunk_size)) { + return -1; + } + } + + /* + * Medley arrays are simple enough, since the smallest disk decides the + * number of sectors used per disk. So there is no need for the cutoff + * magic found in other drivers like hptraid. + */ + if (r->chunk_size_log) { + /* We save some expensive operations (1 div, 1 mul, 1 mod), + * if the chunk size is a power of 2, which is true in most + * cases (at least with my version of the RAID BIOS). + */ + disk = (rsect >> r->chunk_size_log) % r->drives; + rsect = ((rsect / r->sectors_per_row) << + r->chunk_size_log) + (rsect & (r->chunk_size - + 1)); + } else { + disk = (rsect / r->chunk_size) % r->drives; + rsect = rsect / r->sectors_per_row * r->chunk_size + + rsect % r->chunk_size; + } + + dprintk("medley_make_request :-), disk=%d, rsect=%ul\n", disk, + rsect); + bh->b_rdev = r->members[disk]; + bh->b_rsector = rsect; + return 1; +} + +/* + * Find out which array a drive belongs to, and add it to that array. + * If it is not a member of a detected array, add a new array for it. + */ +void medley_add_raiddrive(kdev_t dev, struct medley_metadata *md) +{ + int c; + + dprintk("Candidate drive %02x:%02x - drive %d of %d, stride %d, " + "sectors %ul (%d MB)\n", + MAJOR(dev), MINOR(dev), md->drive_number, + md->drives_per_striped_set, md->chunk_size, + md->total_sectors_low, + md->total_sectors_low / 1024 / 1024 / 2); + + for (c = 0; c < medley_arrays; c++) { + if ((raid[c].timestamp[0] == md->creation_timestamp[0]) && + (raid[c].timestamp[1] == md->creation_timestamp[1]) && + (raid[c].timestamp[2] == md->creation_timestamp[2]) && + (raid[c].drives == md->drives_per_striped_set) && + (raid[c].chunk_size == md->chunk_size) && + ((raid[c].present & (1 << md->drive_number)) == 0)) { + dprintk("Existing array %d\n", c); + raid[c].present |= (1 << md->drive_number); + raid[c].members[md->drive_number] = dev; + break; + } + } + if (c == medley_arrays) { + dprintk("New array %d\n", medley_arrays); + if (medley_arrays == MAX_MEDLEY_ARRAYS) { + printk(KERN_ERR "Medley RAID: " + "Too many RAID sets detected - you can change " + "the max in the driver.\n"); + } else { + raid[c].timestamp[0] = md->creation_timestamp[0]; + raid[c].timestamp[1] = md->creation_timestamp[1]; + raid[c].timestamp[2] = md->creation_timestamp[2]; + raid[c].drives = md->drives_per_striped_set; + raid[c].chunk_size = md->chunk_size; + raid[c].sectors_per_row = md->chunk_size * + md->drives_per_striped_set; + + /* Speedup if chunk size is a power of 2 */ + if (((raid[c].chunk_size - 1) & + (raid[c].chunk_size)) == 0) { + raid[c].chunk_size_log = + ffs(raid[c].chunk_size) - 1; + } else { + raid[c].chunk_size_log = 0; + } + raid[c].present = (1 << md->drive_number); + raid[c].members[md->drive_number] = dev; + if (md->major_ver == 1) { + raid[c].sectors = ((u32 *) (md))[27]; + } else { + raid[c].sectors = md->total_sectors_low; + } + medley_arrays++; + } + } +} + +/* + * Read the Medley metadata from a drive. + * Returns the bh if it was found, otherwise NULL. + */ +struct buffer_head *medley_get_metadata(kdev_t dev) +{ + struct buffer_head *bh = NULL; + struct pci_dev *pcidev; + u32 lba; + int pos; + struct medley_metadata *md; + + ide_drive_t *drvinfo = ide_info_ptr(dev, 0); + if ((drvinfo == NULL) || drvinfo->capacity < 1) { + return NULL; + } + + dprintk("Probing %02x:%02x\n", MAJOR(dev), MINOR(dev)); + + /* If this drive is not on a PCI controller, it is not Medley RAID. + * Medley matches the PCI device ID with the metadata to check if + * it is valid. Unfortunately it is the only reliable way to identify + * the superblock */ + pcidev = drvinfo->hwif ? drvinfo->hwif->pci_dev : NULL; + if (!pcidev) { + return NULL; + } + + /* + * 4 copies of the metadata exist, in the following 4 sectors: + * last, last-0x200, last-0x400, last-0x600. + * + * We must try each of these in order, until we find the metadata. + * FIXME: This does not take into account drives with 48/64-bit LBA + * addressing, even though the Medley RAID version 2 supports these. + */ + lba = drvinfo->capacity - 1; + for (pos = 0; pos < 4; pos++, lba -= 0x200) { + bh = bread(dev, lba, 512); + if (!bh) { + printk(KERN_ERR "Medley RAID (%02x:%02x): " + "Error reading metadata (lba=%d)\n", + MAJOR(dev), MINOR(dev), lba); + break; + } + + /* A valid Medley RAID has the PCI vendor/device ID of its + * IDE controller, and the correct checksum. */ + md = (void *) (bh->b_data); + + if (pcidev->vendor == md->vendor_id && + pcidev->device == md->product_id) { + u16 checksum = 0; + u16 *p = (void *) (bh->b_data); + int c; + for (c = 0; c < 160; c++) { + checksum += *p++; + } + dprintk + ("Probing %02x:%02x csum=%d, major_ver=%d\n", + MAJOR(dev), MINOR(dev), checksum, + md->major_ver); + if (((checksum == 0xffff) && (md->major_ver == 1)) + || (checksum == 0)) { + dprintk("Probing %02x:%02x VALID\n", + MAJOR(dev), MINOR(dev)); + break; + } + } + /* Was not a valid superblock */ + if (bh) { + brelse(bh); + bh = NULL; + } + } + return bh; +} + +/* + * Determine if this drive belongs to a Medley array. + */ +static void medley_probe_drive(int major, int minor) +{ + struct buffer_head *bh; + kdev_t dev = MKDEV(major, minor); + struct medley_metadata *md; + + bh = medley_get_metadata(dev); + if (!bh) + return; + + md = (void *) (bh->b_data); + + if (md->raid_type != 0x0) { + printk(KERN_INFO "Medley RAID (%02x:%02x): " + "Sorry, this driver currently only supports " + "striped sets (RAID level 0).\n", major, minor); + } else if (md->major_ver == 2 && md->total_sectors_high != 0) { + printk(KERN_ERR "Medley RAID (%02x:%02x):" + "Sorry, the driver only supports 32 bit LBA disks " + "(disk too big).\n", major, minor); + } else if (md->major_ver > 0 && md->major_ver > 2) { + printk(KERN_INFO "Medley RAID (%02x:%02x): " + "Unsupported version (%d.%d) - this driver supports " + "Medley version 1.x and 2.x\n", + major, minor, md->major_ver, md->minor_ver); + } else if (md->drives_per_striped_set > MAX_DRIVES_PER_SET) { + printk(KERN_ERR "Medley RAID (%02x:%02x): " + "Striped set too large (%d drives) - please report " + "this (and change max in driver).\n", + major, minor, md->drives_per_striped_set); + } else if ((md->drive_number > md->drives_per_striped_set) || + (md->drives_per_striped_set < 1) || + (md->chunk_size < 1)) { + printk(KERN_ERR "Medley RAID (%02x:%02x): " + "Metadata appears to be corrupt.\n", major, minor); + } else { + /* We have a good candidate, put it in the correct array */ + medley_add_raiddrive(dev, md); + } + + if (bh) { + brelse(bh); + } +} + + +/* + * Taken from hptraid.c, this is called to prevent the device + * from disappearing from under us and also nullifies the (incorrect) + * partitions of the underlying disk. + */ +struct block_device *get_device_lock(kdev_t member) +{ + struct block_device *bdev = bdget(member); + struct gendisk *gd; + int minor = MINOR(member); + int j; + + if (bdev + && blkdev_get(bdev, FMODE_READ | FMODE_WRITE, 0, + BDEV_RAW) == 0) { + /* + * This is supposed to prevent others from + * stealing our underlying disks. Now blank + * the /proc/partitions table for the wrong + * partition table, so that scripts don't + * accidentally mount it and crash the kernel + */ + /* XXX: the 0 is an utter hack --hch */ + gd = get_gendisk(MKDEV(MAJOR(member), 0)); + if (gd != NULL) { + if (gd->major == MAJOR(member)) { + for (j = 1 + (minor << gd->minor_shift); + j < ((minor + 1) << gd->minor_shift); + j++) + gd->part[j].nr_sects = 0; + } + } + } + return bdev; +} + +/* + * Initialise the driver. + */ +static __init int medley_init(void) +{ + int c, d; + + memset(raid, 0, MAX_MEDLEY_ARRAYS * sizeof(struct medley_array)); + + /* Probe each of the drives on our list */ + for (c = 0; probelist[c] != MKDEV(0, 0); c++) { + medley_probe_drive(MAJOR(probelist[c]), + MINOR(probelist[c])); + } + + /* Check if the detected sets are complete */ + for (c = 0; c < medley_arrays; c++) { + if (raid[c].present != (1 << raid[c].drives) - 1) { + printk(KERN_ERR "Medley RAID: " + "Incomplete RAID set deleted - disks:"); + for (d = 0; c < raid[c].drives; c++) { + if (raid[c].present & (1 << d)) { + printk(" %02x:%02x", + MAJOR(raid[c].members[d]), + MINOR(raid[c].members[d])); + } + } + printk("\n"); + if (c + 1 < medley_arrays) { + memmove(raid + c + 1, raid + c, + (medley_arrays - c - + 1) * sizeof(struct medley_array)); + } + medley_arrays--; + } + } + + /* Register any remaining array(s) */ + for (c = 0; c < medley_arrays; c++) { + int device = ataraid_get_device(&medley_ops); + if (device < 0) { + printk(KERN_ERR "Medley RAID: " + "Could not get ATARAID device.\n"); + break; + } + if (c == 0) { + /* First array, compute offset to our device ID's */ + medley_devid_offset = device; + dprintk("Medley_devid_offset: %d\n", + medley_devid_offset); + } else if (device - medley_devid_offset != c) { + printk(KERN_ERR "Medley RAID: " + "ATARAID gave us an illegal device ID.\n"); + ataraid_release_device(device); + break; + } + + printk(KERN_INFO "Medley RAID: " + "Striped set %d consists of %d disks, total %dMiB " + "- disks:", + c, raid[c].drives, + raid[c].sectors / 1024 / 1024 / 2); + for (d = 0; d < raid[c].drives; d++) { + printk(" %02x:%02x", MAJOR(raid[c].members[d]), + MINOR(raid[c].members[d])); + raid[c].bdev[d] = get_device_lock(raid[c].members[d]); + } + printk("\n"); + raid[c].registered = 1; + atomic_set(&(raid[c].valid), 1); + ataraid_register_disk(c, raid[c].sectors); + } + + if (medley_arrays > 0) { + printk(KERN_INFO "Medley RAID: %d active RAID set%s\n", + medley_arrays, medley_arrays == 1 ? "" : "s"); + return 0; + } + + printk(KERN_INFO "Medley RAID: No usable RAID sets found\n"); + return -ENODEV; +} + +/* + * Remove the arrays and clean up. + */ +static void __exit medley_exit(void) +{ + int device, d; + for (device = 0; device < medley_arrays; device++) { + for (d = 0; d < raid[device].drives; d++) { + if (raid[device].bdev[d]) { + blkdev_put(raid[device].bdev[d], BDEV_RAW); + raid[device].bdev[d] = NULL; + } + } + if (raid[device].registered) { + ataraid_release_device(device + + medley_devid_offset); + raid[device].registered = 0; + } + } +} + +/* + * Called to open the virtual device + */ +static int medley_open(struct inode *inode, struct file *filp) +{ + int device = ((inode->i_rdev >> SHIFT) & MAJOR_MASK) - + medley_devid_offset; + dprintk("medley_open\n"); + + if (device < medley_arrays) { + while (!atomic_read(&(raid[device].valid))) + sleep_on(&medley_wait_open); + raid[device].access++; + MOD_INC_USE_COUNT; + return (0); + } + return -ENODEV; +} + +/* + * Called to release the handle on the virtual device + */ +static int medley_release(struct inode *inode, struct file *filp) +{ + int device = ((inode->i_rdev >> SHIFT) & MAJOR_MASK) - + medley_devid_offset; + dprintk("medley_release\n"); + raid[device].access--; + MOD_DEC_USE_COUNT; + return 0; +} + +module_init(medley_init); +module_exit(medley_exit); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.25/drivers/ieee1394/dma.c linux-2.4.26/drivers/ieee1394/dma.c --- linux-2.4.25/drivers/ieee1394/dma.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.26/drivers/ieee1394/dma.c 2004-04-14 06:05:30.000000000 -0700 @@ -86,7 +86,7 @@ memset(dma->kvirt, 0, n_pages * PAGE_SIZE); /* allocate scatter/gather list */ - dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL); + dma->sglist = vmalloc(dma->n_pages * sizeof(struct scatterlist)); if (!dma->sglist) { printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n"); goto err; @@ -130,7 +130,7 @@ } if (dma->sglist) { - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; } diff -urN linux-2.4.25/drivers/ieee1394/video1394.c linux-2.4.26/drivers/ieee1394/video1394.c --- linux-2.4.25/drivers/ieee1394/video1394.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/ieee1394/video1394.c 2004-04-14 06:05:30.000000000 -0700 @@ -216,6 +216,7 @@ d->frame_size = buf_size; d->buf_size = PAGE_ALIGN(buf_size); d->last_buffer = -1; + INIT_LIST_HEAD(&d->link); init_waitqueue_head(&d->waitq); /* Init the regions for easy cleanup */ diff -urN linux-2.4.25/drivers/input/input.c linux-2.4.26/drivers/input/input.c --- linux-2.4.25/drivers/input/input.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.26/drivers/input/input.c 2004-04-14 06:05:30.000000000 -0700 @@ -422,7 +422,7 @@ static int __init input_init(void) { if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) { - printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); + printk(KERN_ERR "input: unable to register char major %d\n", INPUT_MAJOR); return -EBUSY; } input_devfs_handle = devfs_mk_dir(NULL, "input", NULL); diff -urN linux-2.4.25/drivers/isdn/avmb1/capidrv.c linux-2.4.26/drivers/isdn/avmb1/capidrv.c --- linux-2.4.25/drivers/isdn/avmb1/capidrv.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.26/drivers/isdn/avmb1/capidrv.c 2004-04-14 06:05:30.000000000 -0700 @@ -523,13 +523,25 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg) { - struct sk_buff *skb; - size_t len; + struct sk_buff *skb; + size_t len; + u16 err; + capi_cmsg2message(cmsg, cmsg->buf); len = CAPIMSG_LEN(cmsg->buf); skb = alloc_skb(len, GFP_ATOMIC); + if(!skb) { + printk(KERN_ERR "no skb len(%d) memory\n", len); + return; + } memcpy(skb_put(skb, len), cmsg->buf, len); - (*capifuncs->capi_put_message) (global.appid, skb); + err = (*capifuncs->capi_put_message) (global.appid, skb); + if (err) { + printk(KERN_WARNING "%s: capi_put_message error: %04x\n", + __FUNCTION__, err); + kfree_skb(skb); + return; + } global.nsentctlpkt++; } @@ -2188,10 +2200,10 @@ free_ncci(card, card->bchans[card->nbchan-1].nccip); if (card->bchans[card->nbchan-1].plcip) free_plci(card, card->bchans[card->nbchan-1].plcip); - if (card->plci_list) - printk(KERN_ERR "capidrv: bug in free_plci()\n"); card->nbchan--; } + if (card->plci_list) + printk(KERN_ERR "capidrv: bug in free_plci()\n"); kfree(card->bchans); card->bchans = 0; diff -urN linux-2.4.25/drivers/isdn/avmb1/kcapi.c linux-2.4.26/drivers/isdn/avmb1/kcapi.c --- linux-2.4.25/drivers/isdn/avmb1/kcapi.c 2003-06-13 07:51:34.000000000 -0700 +++ linux-2.4.26/drivers/isdn/avmb1/kcapi.c 2004-04-14 06:05:30.000000000 -0700 @@ -546,7 +546,13 @@ static void notify_up(__u32 contr) { struct capi_interface_user *p; + __u16 appl; + for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { + if (!VALID_APPLID(appl)) continue; + if (APPL(appl)->releasing) continue; + CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam); + } printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); spin_lock(&capi_users_lock); for (p = capi_users; p; p = p->next) { @@ -714,12 +720,16 @@ nextpp = &(*pp)->next; } } - APPL(appl)->releasing--; - if (APPL(appl)->releasing <= 0) { - APPL(appl)->signal = 0; - APPL_MARK_FREE(appl); - printk(KERN_INFO "kcapi: appl %d down\n", appl); - } + if (APPL(appl)->releasing) { /* only release if the application was marked for release */ + printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing); + APPL(appl)->releasing--; + if (APPL(appl)->releasing <= 0) { + APPL(appl)->signal = 0; + APPL_MARK_FREE(appl); + printk(KERN_INFO "kcapi: appl %d down\n", appl); + } + } else + printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr); } /* * ncci management @@ -872,16 +882,7 @@ static void controllercb_ready(struct capi_ctr * card) { - __u16 appl; - card->cardstate = CARD_RUNNING; - - for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { - if (!VALID_APPLID(appl)) continue; - if (APPL(appl)->releasing) continue; - card->driver->register_appl(card, appl, &APPL(appl)->rparam); - } - printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", CARDNR(card), card->name); diff -urN linux-2.4.25/drivers/isdn/hisax/isurf.c linux-2.4.26/drivers/isdn/hisax/isurf.c --- linux-2.4.25/drivers/isdn/hisax/isurf.c 2002-11-28 15:53:13.000000000 -0800 +++ linux-2.4.26/drivers/isdn/hisax/isurf.c 2004-04-14 06:05:30.000000000 -0700 @@ -235,8 +235,18 @@ pd->prepare(pd); pd->deactivate(pd); pd->activate(pd); + /* The ISA-PnP logic apparently + * expects upper limit address to be + * set. Since the isa-pnp module + * doesn't do this, so we have to make + * up for it. + */ + isapnp_cfg_begin(pd->bus->number, pd->devfn); + isapnp_write_word(ISAPNP_CFG_MEM+3, + pd->resource[8].end >> 8); + isapnp_cfg_end(); cs->hw.isurf.reset = pd->resource[0].start; - cs->hw.isurf.phymem = pd->resource[1].start; + cs->hw.isurf.phymem = pd->resource[8].start; cs->irq = pd->irq_resource[0].start; if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", diff -urN linux-2.4.25/drivers/md/lvm-snap.c linux-2.4.26/drivers/md/lvm-snap.c --- linux-2.4.25/drivers/md/lvm-snap.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/md/lvm-snap.c 2004-04-14 06:05:30.000000000 -0700 @@ -554,17 +554,15 @@ int lvm_snapshot_alloc(lv_t * lv_snap) { - int ret, max_sectors; + int ret; /* allocate kiovec to do chunk io */ ret = alloc_kiovec(1, &lv_snap->lv_iobuf); if (ret) goto out; - max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT - 9); - - ret = - lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); + ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, + KIO_MAX_SECTORS); if (ret) goto out_free_kiovec; diff -urN linux-2.4.25/drivers/md/raid1.c linux-2.4.26/drivers/md/raid1.c --- linux-2.4.25/drivers/md/raid1.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/md/raid1.c 2004-04-14 06:05:30.000000000 -0700 @@ -487,6 +487,12 @@ goto rb_out; +#if defined(CONFIG_ALPHA) && ((__GNUC__ < 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ < 3))) + /* Work around a compiler bug in older gcc */ + new_disk = *(volatile int *)&new_disk; +#endif + /* make sure that disk is operational */ while( !conf->mirrors[new_disk].operational) { if (new_disk <= 0) new_disk = conf->raid_disks; @@ -544,6 +550,11 @@ /* Find the disk which is closest */ +#if defined(CONFIG_ALPHA) && ((__GNUC__ < 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ < 3))) + /* Work around a compiler bug in older gcc */ + disk = *(volatile int *)&disk; +#endif do { if (disk <= 0) disk = conf->raid_disks; diff -urN linux-2.4.25/drivers/media/video/Config.in linux-2.4.26/drivers/media/video/Config.in --- linux-2.4.25/drivers/media/video/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/media/video/Config.in 2004-04-14 06:05:30.000000000 -0700 @@ -49,7 +49,7 @@ dep_tristate ' Miro DC10(+) support' CONFIG_VIDEO_ZORAN_DC10 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C dep_tristate ' Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HIGHMEM64G" != "y" ]; then dep_tristate ' Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI fi diff -urN linux-2.4.25/drivers/media/video/meye.c linux-2.4.26/drivers/media/video/meye.c --- linux-2.4.25/drivers/media/video/meye.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/media/video/meye.c 2004-04-14 06:05:30.000000000 -0700 @@ -188,23 +188,31 @@ free_pages((unsigned long)vaddr, get_order(size)); } -/* return a page table pointing to N pages of locked memory */ +/* + * return a page table pointing to N pages of locked memory + * + * NOTE: The meye device expects dma_addr_t size to be 32 bits + * (the toc must be exactly 1024 entries each of them being 4 bytes + * in size, the whole result being 4096 bytes). We're using here + * dma_addr_t for correctness but the compilation of this driver is + * disabled for HIGHMEM64G=y, where sizeof(dma_addr_t) != 4 + */ static int ptable_alloc(void) { - u32 *pt; + dma_addr_t *pt; int i; memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - meye.mchip_ptable[MCHIP_NB_PAGES] = dma_alloc_coherent(meye.mchip_dev, - PAGE_SIZE, - &meye.mchip_dmahandle, - GFP_KERNEL); - if (!meye.mchip_ptable[MCHIP_NB_PAGES]) { + meye.mchip_ptable_toc = dma_alloc_coherent(meye.mchip_dev, + PAGE_SIZE, + &meye.mchip_dmahandle, + GFP_KERNEL); + if (!meye.mchip_ptable_toc) { meye.mchip_dmahandle = 0; return -1; } - pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES]; + pt = meye.mchip_ptable_toc; for (i = 0; i < MCHIP_NB_PAGES; i++) { meye.mchip_ptable[i] = dma_alloc_coherent(meye.mchip_dev, PAGE_SIZE, @@ -212,13 +220,18 @@ GFP_KERNEL); if (!meye.mchip_ptable[i]) { int j; - pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES]; + pt = meye.mchip_ptable_toc; for (j = 0; j < i; ++j) { dma_free_coherent(meye.mchip_dev, PAGE_SIZE, meye.mchip_ptable[j], *pt); pt++; } + dma_free_coherent(meye.mchip_dev, + PAGE_SIZE, + meye.mchip_ptable_toc, + meye.mchip_dmahandle); + meye.mchip_ptable_toc = 0; meye.mchip_dmahandle = 0; return -1; } @@ -228,10 +241,10 @@ } static void ptable_free(void) { - u32 *pt; + dma_addr_t *pt; int i; - pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES]; + pt = meye.mchip_ptable_toc; for (i = 0; i < MCHIP_NB_PAGES; i++) { if (meye.mchip_ptable[i]) dma_free_coherent(meye.mchip_dev, @@ -240,13 +253,14 @@ pt++; } - if (meye.mchip_ptable[MCHIP_NB_PAGES]) + if (meye.mchip_ptable_toc) dma_free_coherent(meye.mchip_dev, PAGE_SIZE, - meye.mchip_ptable[MCHIP_NB_PAGES], + meye.mchip_ptable_toc, meye.mchip_dmahandle); memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); + meye.mchip_ptable_toc = 0; meye.mchip_dmahandle = 0; } diff -urN linux-2.4.25/drivers/media/video/meye.h linux-2.4.26/drivers/media/video/meye.h --- linux-2.4.25/drivers/media/video/meye.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/media/video/meye.h 2004-04-14 06:05:30.000000000 -0700 @@ -31,7 +31,7 @@ #define _MEYE_PRIV_H_ #define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 8 +#define MEYE_DRIVER_MINORVERSION 9 #include #include @@ -298,7 +298,8 @@ u8 mchip_fnum; /* current mchip frame number */ unsigned char *mchip_mmregs; /* mchip: memory mapped registers */ - u8 *mchip_ptable[MCHIP_NB_PAGES+1];/* mchip: ptable + ptable toc */ + u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */ + dma_addr_t *mchip_ptable_toc; /* mchip: ptable toc */ dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ unsigned char *grab_fbuffer; /* capture framebuffer */ diff -urN linux-2.4.25/drivers/net/8139too.c linux-2.4.26/drivers/net/8139too.c --- linux-2.4.25/drivers/net/8139too.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/8139too.c 2004-04-14 06:05:30.000000000 -0700 @@ -255,6 +255,10 @@ {0x11db, 0x1234, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x1432, 0x9130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, {0x02ac, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x018a, 0x0106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x126c, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x1743, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, + {0x021b, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 }, #ifdef CONFIG_SH_SECUREEDGE5410 /* Bogus 8139 silicon reports 8129 without external PROM :-( */ @@ -953,12 +957,11 @@ if (i < 0) return i; + assert (dev != NULL); tp = dev->priv; + assert (tp != NULL); ioaddr = tp->mmio_addr; - assert (ioaddr != NULL); - assert (dev != NULL); - assert (tp != NULL); addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) diff -urN linux-2.4.25/drivers/net/Config.in linux-2.4.26/drivers/net/Config.in --- linux-2.4.25/drivers/net/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/Config.in 2004-04-14 06:05:30.000000000 -0700 @@ -198,6 +198,7 @@ dep_tristate ' Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI dep_tristate ' National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI + dep_tristate ' nForce Ethernet support (EXPERIMENTAL)' CONFIG_FORCEDETH $CONFIG_PCI $CONFIG_EXPERIMENTAL dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL dep_tristate ' RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL diff -urN linux-2.4.25/drivers/net/Makefile linux-2.4.26/drivers/net/Makefile --- linux-2.4.25/drivers/net/Makefile 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/Makefile 2004-04-14 06:05:30.000000000 -0700 @@ -154,6 +154,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o +obj-$(CONFIG_FORCEDETH) += forcedeth.o obj-$(CONFIG_PPP) += ppp_generic.o slhc.o obj-$(CONFIG_PPP_ASYNC) += ppp_async.o diff -urN linux-2.4.25/drivers/net/bonding/bond_3ad.c linux-2.4.26/drivers/net/bonding/bond_3ad.c --- linux-2.4.25/drivers/net/bonding/bond_3ad.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/net/bonding/bond_3ad.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel 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 @@ -47,8 +47,13 @@ * - Send LACPDU as highest priority packet to further fix the above * problem on very high Tx traffic load where packets may get dropped * by the slave. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -119,6 +124,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; +static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; // ================= 3AD api to bonding and kernel code ================== static u16 __get_link_speed(struct port *port); @@ -196,13 +202,11 @@ */ static inline struct port *__get_first_port(struct bonding *bond) { - struct slave *slave = bond->next; - - if (slave == (struct slave *)bond) { + if (bond->slave_cnt == 0) { return NULL; } - return &(SLAVE_AD_INFO(slave).port); + return &(SLAVE_AD_INFO(bond->first_slave).port); } /** @@ -218,7 +222,7 @@ struct slave *slave = port->slave; // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -236,12 +240,12 @@ { struct bonding *bond = __get_bond_by_port(port); - // If there's no bond for this port, or this is the last slave - if ((bond == NULL) || (bond->next == (struct slave *)bond)) { + // If there's no bond for this port, or bond has no slaves + if ((bond == NULL) || (bond->slave_cnt == 0)) { return NULL; } - return &(SLAVE_AD_INFO(bond->next).aggregator); + return &(SLAVE_AD_INFO(bond->first_slave).aggregator); } /** @@ -257,7 +261,7 @@ struct bonding *bond = bond_get_bond_by_slave(slave); // If there's no bond for this aggregator, or this is the last slave - if ((bond == NULL) || (slave->next == bond->next)) { + if ((bond == NULL) || (slave->next == bond->first_slave)) { return NULL; } @@ -392,7 +396,7 @@ } } - BOND_PRINT_DBG(("Port %d Received link speed %d update from adapter", port->actor_port_number, speed)); + dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -418,12 +422,12 @@ switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - BOND_PRINT_DBG(("Port %d Received status full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - BOND_PRINT_DBG(("Port %d Received status NOT full duplex update from adapter", port->actor_port_number)); + dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -1059,7 +1063,7 @@ // check if the state machine was changed if (port->sm_mux_state != last_state) { - BOND_PRINT_DBG(("Mux Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_mux_state)); + dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1158,7 +1162,7 @@ // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - BOND_PRINT_DBG(("Rx Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_rx_state)); + dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1204,7 +1208,7 @@ // detect loopback situation if (!MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->actor_system))) { // INFO_RECEIVED_LOOPBACK_FRAMES - printk(KERN_ERR "bonding: An illegal loopback occurred on adapter (%s)\n", + printk(KERN_ERR DRV_NAME ": An illegal loopback occurred on adapter (%s)\n", port->slave->dev->name); printk(KERN_ERR "Check the configuration to verify that all Adapters " "are connected to 802.3ad compliant switch ports\n"); @@ -1245,7 +1249,7 @@ __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { - BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number)); + dprintk("Sent LACPDU on port %d\n", port->actor_port_number); // mark ntt as false, so it will not be sent again until demanded port->ntt = 0; } @@ -1318,7 +1322,7 @@ // check if the state machine was changed if (port->sm_periodic_state != last_state) { - BOND_PRINT_DBG(("Periodic Machine: Port=%d, Last State=%d, Curr State=%d", port->actor_port_number, last_state, port->sm_periodic_state)); + dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1375,7 +1379,7 @@ port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - BOND_PRINT_DBG(("Port %d left LAG %d", port->actor_port_number, temp_aggregator->aggregator_identifier)); + dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1384,7 +1388,7 @@ } } if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - printk(KERN_WARNING "bonding: Warning: Port %d (on %s) was " + printk(KERN_WARNING DRV_NAME ": Warning: Port %d (on %s) was " "related to aggregator %d but was not on its port list\n", port->actor_port_number, port->slave->dev->name, port->aggregator->aggregator_identifier); @@ -1417,7 +1421,7 @@ port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - BOND_PRINT_DBG(("Port %d joined LAG %d(existing LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1454,9 +1458,9 @@ // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - BOND_PRINT_DBG(("Port %d joined LAG %d(new LAG)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { - printk(KERN_ERR "bonding: Port %d (on %s) did not find a suitable aggregator\n", + printk(KERN_ERR DRV_NAME ": Port %d (on %s) did not find a suitable aggregator\n", port->actor_port_number, port->slave->dev->name); } } @@ -1580,30 +1584,30 @@ aggregator; aggregator = __get_next_agg(aggregator)) { - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", aggregator->aggregator_identifier, aggregator->num_of_ports, aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active)); + aggregator->is_individual, aggregator->is_active); } // check if any partner replys if (best_aggregator->is_individual) { - printk(KERN_WARNING "bonding: Warning: No 802.3ad response from the link partner " + printk(KERN_WARNING DRV_NAME ": Warning: No 802.3ad response from the link partner " "for any adapters in the bond\n"); } // check if there are more than one aggregator if (num_of_aggs > 1) { - BOND_PRINT_DBG(("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond")); + dprintk("Warning: More than one Link Aggregation Group was " + "found in the bond. Only one group will function in the bond\n"); } best_aggregator->is_active = 1; - BOND_PRINT_DBG(("LAG %d choosed as the active LAG", best_aggregator->aggregator_identifier)); - BOND_PRINT_DBG(("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d", + dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); + dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active)); + best_aggregator->is_individual, best_aggregator->is_active); // disable the ports that were related to the former active_aggregator if (last_active_aggregator) { @@ -1644,7 +1648,7 @@ aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - BOND_PRINT_DBG(("LAG %d was cleared", aggregator->aggregator_identifier)); + dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1729,7 +1733,7 @@ static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - BOND_PRINT_DBG(("Enabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1742,7 +1746,7 @@ static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - BOND_PRINT_DBG(("Disabling port %d(LAG %d)", port->actor_port_number, port->aggregator->aggregator_identifier)); + dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1780,7 +1784,7 @@ // send the marker information if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Information on port %d", port->actor_port_number)); + dprintk("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1803,7 +1807,7 @@ // send the marker response if (ad_marker_send(port, &marker) >= 0) { - BOND_PRINT_DBG(("Sent Marker Response on port %d", port->actor_port_number)); + dprintk("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1890,13 +1894,13 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast) { // check that the bond is not initialized yet - if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->device->dev_addr))) { + if (MAC_ADDRESS_COMPARE(&(BOND_AD_INFO(bond).system.sys_mac_addr), &(bond->dev->dev_addr))) { aggregator_identifier = 0; BOND_AD_INFO(bond).lacp_fast = lacp_fast; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; - BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->device->dev_addr); + BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; @@ -1921,7 +1925,7 @@ struct aggregator *aggregator; if (bond == NULL) { - printk(KERN_CRIT "The slave %s is not attached to its bond\n", slave->dev->name); + printk(KERN_ERR "The slave %s is not attached to its bond\n", slave->dev->name); return -1; } @@ -1964,7 +1968,7 @@ ad_initialize_agg(aggregator); - aggregator->aggregator_mac_address = *((struct mac_addr *)bond->device->dev_addr); + aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); aggregator->aggregator_identifier = (++aggregator_identifier); aggregator->slave = slave; aggregator->is_active = 0; @@ -1996,11 +2000,11 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Trying to unbind an uninitialized port on %s\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Trying to unbind an uninitialized port on %s\n", slave->dev->name); return; } - BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); + dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -2024,10 +2028,10 @@ // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - BOND_PRINT_DBG(("Some port(s) related to LAG %d - replaceing with LAG %d", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier)); + dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { - printk(KERN_INFO "bonding: Removing an active aggregator\n"); + printk(KERN_INFO DRV_NAME ": Removing an active aggregator\n"); // select new active aggregator select_new_active_agg = 1; } @@ -2057,7 +2061,7 @@ ad_agg_selection_logic(__get_first_agg(port)); } } else { - printk(KERN_WARNING "bonding: Warning: unbinding aggregator, " + printk(KERN_WARNING DRV_NAME ": Warning: unbinding aggregator, " "and could not find a new aggregator for its ports\n"); } } else { // in case that the only port related to this aggregator is the one we want to remove @@ -2072,7 +2076,7 @@ } } - BOND_PRINT_DBG(("Unbinding port %d", port->actor_port_number)); + dprintk("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2123,13 +2127,13 @@ read_lock(&bond->lock); - //check if there are any slaves - if (bond->next == (struct slave *)bond) { - goto end; + if (bond->kill_timers) { + goto out; } - if ((bond->device->flags & IFF_UP) != IFF_UP) { - goto end; + //check if there are any slaves + if (bond->slave_cnt == 0) { + goto re_arm; } // check if agg_select_timer timer after initialize is timed out @@ -2137,8 +2141,8 @@ // select the active aggregator for the bond if ((port = __get_first_port(bond))) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: bond's first port is uninitialized\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: bond's first port is uninitialized\n"); + goto re_arm; } aggregator = __get_first_agg(port); @@ -2149,8 +2153,8 @@ // for each port run the state machines for (port = __get_first_port(bond); port; port = __get_next_port(port)) { if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: Found an uninitialized port\n"); - goto end; + printk(KERN_WARNING DRV_NAME ": Warning: Found an uninitialized port\n"); + goto re_arm; } ad_rx_machine(NULL, port); @@ -2165,14 +2169,10 @@ } } -end: +re_arm: + mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks); +out: read_unlock(&bond->lock); - - - if ((bond->device->flags & IFF_UP) == IFF_UP) { - /* re-arm the timer */ - mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + (AD_TIMER_INTERVAL * HZ / 1000)); - } } /** @@ -2194,14 +2194,14 @@ port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: port of slave %s is uninitialized\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME ": Warning: port of slave %s is uninitialized\n", slave->dev->name); return; } switch (lacpdu->subtype) { case AD_TYPE_LACPDU: __ntohs_lacpdu(lacpdu); - BOND_PRINT_DBG(("Received LACPDU on port %d", port->actor_port_number)); + dprintk("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2210,17 +2210,17 @@ switch (((struct marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Information on port %d", port->actor_port_number)); + dprintk("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - BOND_PRINT_DBG(("Received Marker Response on port %d", port->actor_port_number)); + dprintk("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct marker *)lacpdu, port); break; default: - BOND_PRINT_DBG(("Received an unknown Marker subtype on slot %d", port->actor_port_number)); + dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2240,14 +2240,14 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: speed changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: speed changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - BOND_PRINT_DBG(("Port %d changed speed", port->actor_port_number)); + dprintk("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2267,14 @@ // if slave is null, the whole port is not initialized if (!port->slave) { - printk(KERN_WARNING "bonding: Warning: duplex changed for uninitialized port on %s\n", + printk(KERN_WARNING DRV_NAME ": Warning: duplex changed for uninitialized port on %s\n", slave->dev->name); return; } port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - BOND_PRINT_DBG(("Port %d changed duplex", port->actor_port_number)); + dprintk("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2295,10 +2295,8 @@ // if slave is null, the whole port is not initialized if (!port->slave) { -#ifdef BONDING_DEBUG - printk(KERN_WARNING "bonding: Warning: link status changed for uninitialized port on %s\n", - slave->dev->name); -#endif + printk(KERN_WARNING DRV_NAME ": Warning: link status changed for uninitialized port on %s\n", + slave->dev->name); return; } @@ -2356,41 +2354,28 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct slave *slave, *start_at; + struct bonding *bond = dev->priv; struct ethhdr *data = (struct ethhdr *)skb->data; int slave_agg_no; int slaves_in_agg; int agg_id; + int i; struct ad_info ad_info; + int res = 1; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } - - if (bond == NULL) { - printk(KERN_CRIT "bonding: Error: bond is NULL on device %s\n", dev->name); - dev_kfree_skb(skb); - return 0; - } - + /* make sure that the slaves list will + * not change during tx + */ read_lock(&bond->lock); - slave = bond->prev; - /* check if bond is empty */ - if ((slave == (struct slave *) bond) || (bond->slave_cnt == 0)) { - printk(KERN_DEBUG "ERROR: bond is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto out; } if (bond_3ad_get_active_agg_info(bond, &ad_info)) { printk(KERN_DEBUG "ERROR: bond_3ad_get_active_agg_info failed\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto out; } slaves_in_agg = ad_info.ports; @@ -2399,21 +2384,12 @@ if (slaves_in_agg == 0) { /*the aggregator is empty*/ printk(KERN_DEBUG "ERROR: active aggregator is empty\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + goto out; } - /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } + slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg; - slave_agg_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % slaves_in_agg; - while (slave != (slave_t *)bond) { + bond_for_each_slave(bond, slave, i) { struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg && (agg->aggregator_identifier == agg_id)) { @@ -2422,61 +2398,41 @@ break; } } - - slave = slave->prev; - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } } - if (slave == (slave_t *)bond) { - printk(KERN_ERR "bonding: Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (slave_agg_no >= 0) { + printk(KERN_ERR DRV_NAME ": Error: Couldn't find a slave to tx on for aggregator ID %d\n", agg_id); + goto out; } start_at = slave; - do { + bond_for_each_slave_from(bond, slave, i, start_at) { int slave_agg_id = 0; - struct aggregator *agg; - - if (slave == NULL) { - printk(KERN_ERR "bonding: Error: slave is NULL\n"); - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; - } - - agg = SLAVE_AD_INFO(slave).port.aggregator; + struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator; if (agg) { slave_agg_id = agg->aggregator_identifier; } - if (SLAVE_IS_OK(slave) && - agg && (slave_agg_id == agg_id)) { - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; + if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) { + res = bond_dev_queue_xmit(bond, skb, slave->dev); + break; } - } while ((slave = slave->next) != start_at); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } read_unlock(&bond->lock); return 0; } int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype) { - struct bonding *bond = (struct bonding *)dev->priv; + struct bonding *bond = dev->priv; struct slave *slave = NULL; int ret = NET_RX_DROP; diff -urN linux-2.4.25/drivers/net/bonding/bond_3ad.h linux-2.4.26/drivers/net/bonding/bond_3ad.h --- linux-2.4.25/drivers/net/bonding/bond_3ad.h 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/net/bonding/bond_3ad.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel 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 @@ -28,6 +28,9 @@ * 2003/05/01 - Shmulik Hen * - Renamed bond_3ad_link_status_changed() to * bond_3ad_handle_link_change() for compatibility with TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_3AD_H__ diff -urN linux-2.4.25/drivers/net/bonding/bond_alb.c linux-2.4.26/drivers/net/bonding/bond_alb.c --- linux-2.4.25/drivers/net/bonding/bond_alb.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/bonding/bond_alb.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel 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 @@ -28,8 +28,19 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * + * 2003/12/30 - Amir Noam + * - Fixed: Cannot remove and re-enslave the original active slave. + * + * 2004/01/14 - Shmulik Hen + * - Add capability to tag self generated packets in ALB/TLB modes. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -42,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -50,11 +62,11 @@ #define ALB_TIMER_TICKS_PER_SEC 10 /* should be a divisor of HZ */ -#define BOND_TLB_REBALANCE_INTERVAL 10 /* in seconds, periodic re-balancing - * used for division - never set +#define BOND_TLB_REBALANCE_INTERVAL 10 /* In seconds, periodic re-balancing. + * Used for division - never set * to zero !!! */ -#define BOND_ALB_LP_INTERVAL 1 /* in seconds periodic send of +#define BOND_ALB_LP_INTERVAL 1 /* In seconds, periodic send of * learning packets to the switch */ @@ -66,12 +78,12 @@ #define TLB_HASH_TABLE_SIZE 256 /* The size of the clients hash table. * Note that this value MUST NOT be smaller - * because the key hash table BYTE wide ! + * because the key hash table is BYTE wide ! */ #define TLB_NULL_INDEX 0xffffffff -#define MAX_LP_RETRY 3 +#define MAX_LP_BURST 3 /* rlb defs */ #define RLB_HASH_TABLE_SIZE 256 @@ -86,12 +98,15 @@ */ #define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC +static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC; + #pragma pack(1) struct learning_pkt { u8 mac_dst[ETH_ALEN]; u8 mac_src[ETH_ALEN]; u16 type; - u8 padding[ETH_ZLEN - (2*ETH_ALEN + 2)]; + u8 padding[ETH_ZLEN - ETH_HLEN]; }; struct arp_pkt { @@ -110,13 +125,12 @@ /* Forward declaration */ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]); -static inline u8 -_simple_hash(u8 *hash_start, int hash_size) +static inline u8 _simple_hash(u8 *hash_start, int hash_size) { int i; u8 hash = 0; - for (i=0; iload_history = 1 + entry->tx_bytes / - BOND_TLB_REBALANCE_INTERVAL; + BOND_TLB_REBALANCE_INTERVAL; entry->tx_bytes = 0; } + entry->tx_slave = NULL; entry->next = TLB_NULL_INDEX; entry->prev = TLB_NULL_INDEX; } -static inline void -tlb_init_slave(struct slave *slave) +static inline void tlb_init_slave(struct slave *slave) { - struct tlb_slave_info *slave_info = &(SLAVE_TLB_INFO(slave)); - - slave_info->load = 0; - slave_info->head = TLB_NULL_INDEX; + SLAVE_TLB_INFO(slave).load = 0; + SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } /* Caller must hold bond lock for read */ -static inline void -tlb_clear_slave(struct bonding *bond, struct slave *slave, u8 save_load) +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) { - struct tlb_client_info *tx_hash_table = NULL; - u32 index, next_index; + struct tlb_client_info *tx_hash_table; + u32 index; - /* clear slave from tx_hashtbl */ _lock_tx_hashtbl(bond); + + /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; - if (tx_hash_table) { - index = SLAVE_TLB_INFO(slave).head; - while (index != TLB_NULL_INDEX) { - next_index = tx_hash_table[index].next; - tlb_init_table_entry(bond, index, save_load); - index = next_index; - } + index = SLAVE_TLB_INFO(slave).head; + while (index != TLB_NULL_INDEX) { + u32 next_index = tx_hash_table[index].next; + tlb_init_table_entry(&tx_hash_table[index], save_load); + index = next_index; } + _unlock_tx_hashtbl(bond); tlb_init_slave(slave); } /* Must be called before starting the monitor timer */ -static int -tlb_initialize(struct bonding *bond) +static int tlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + int size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); int i; - size_t size; - -#if(TLB_HASH_TABLE_SIZE != 256) - /* Key to the hash table is byte wide. Check the size! */ - #error Hash Table size is wrong. -#endif spin_lock_init(&(bond_info->tx_hashtbl_lock)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl != NULL) { - printk (KERN_ERR "%s: TLB hash table is not NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return -1; - } - size = TLB_HASH_TABLE_SIZE * sizeof(struct tlb_client_info); bond_info->tx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->tx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate TLB hash table\n", - bond->device->name); + if (!bond_info->tx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate TLB hash table\n", + bond->dev->name); _unlock_tx_hashtbl(bond); return -1; } memset(bond_info->tx_hashtbl, 0, size); - for (i=0; itx_hashtbl[i], 1); } + _unlock_tx_hashtbl(bond); return 0; } /* Must be called only after all slaves have been released */ -static void -tlb_deinitialize(struct bonding *bond) +static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); _lock_tx_hashtbl(bond); - if (bond_info->tx_hashtbl == NULL) { - _unlock_tx_hashtbl(bond); - return; - } + kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; + _unlock_tx_hashtbl(bond); } /* Caller must hold bond lock for read */ -static struct slave* -tlb_get_least_loaded_slave(struct bonding *bond) +static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) { - struct slave *slave; - struct slave *least_loaded; - s64 curr_gap, max_gap; + struct slave *slave, *least_loaded; + s64 max_gap; + int i, found = 0; /* Find the first enabled slave */ - slave = bond_get_first_slave(bond); - while (slave) { + bond_for_each_slave(bond, slave, i) { if (SLAVE_IS_OK(slave)) { + found = 1; break; } - slave = bond_get_next_slave(bond, slave); } - if (!slave) { + if (!found) { return NULL; } least_loaded = slave; - max_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); + max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */ + (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */ /* Find the slave with the largest gap */ - slave = bond_get_next_slave(bond, slave); - while (slave) { + bond_for_each_slave_from(bond, slave, i, least_loaded) { if (SLAVE_IS_OK(slave)) { - curr_gap = (s64)(slave->speed * 1000000) - - (s64)(SLAVE_TLB_INFO(slave).load * 8); - if (max_gap < curr_gap) { + s64 gap = (s64)(slave->speed << 20) - + (s64)(SLAVE_TLB_INFO(slave).load << 3); + if (max_gap < gap) { least_loaded = slave; - max_gap = curr_gap; + max_gap = gap; } } - slave = bond_get_next_slave(bond, slave); } return least_loaded; } /* Caller must hold bond lock for read */ -struct slave* -tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct tlb_client_info *hash_table = NULL; - struct slave *assigned_slave = NULL; + struct tlb_client_info *hash_table; + struct slave *assigned_slave; _lock_tx_hashtbl(bond); hash_table = bond_info->tx_hashtbl; - if (hash_table == NULL) { - printk (KERN_ERR "%s: TLB hash table is NULL\n", - bond->device->name); - _unlock_tx_hashtbl(bond); - return NULL; - } - assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { assigned_slave = tlb_get_least_loaded_slave(bond); @@ -345,14 +317,12 @@ } /*********************** rlb specific functions ***************************/ -static inline void -_lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl(struct bonding *bond) { spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void -_unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl(struct bonding *bond) { spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } @@ -360,26 +330,20 @@ /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ -static void -rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) +static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = _simple_hash((u8*)&(arp->ip_src), 4); + hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->assigned) && (client_info->ip_src == arp->ip_dst) && (client_info->ip_dst == arp->ip_src)) { - /* update the clients MAC address */ memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); client_info->ntt = 1; @@ -389,66 +353,60 @@ _unlock_rx_hashtbl(bond); } -static int -rlb_arp_recv(struct sk_buff *skb, - struct net_device *dev, - struct packet_type* ptype) +static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype) { - struct bonding *bond = (struct bonding *)dev->priv; - int ret = NET_RX_DROP; + struct bonding *bond = bond_dev->priv; struct arp_pkt *arp = (struct arp_pkt *)skb->data; + int res = NET_RX_DROP; - if (!(dev->flags & IFF_MASTER)) { + if (!(bond_dev->flags & IFF_MASTER)) { goto out; } if (!arp) { - printk(KERN_ERR "Packet has no ARP data\n"); + dprintk("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - printk(KERN_ERR "Packet is too small to be an ARP\n"); + dprintk("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ rlb_update_entry_from_arp(bond, arp); - BOND_PRINT_DBG(("Server received an ARP Reply from client")); + dprintk("Server received an ARP Reply from client\n"); } - ret = NET_RX_SUCCESS; + res = NET_RX_SUCCESS; out: dev_kfree_skb(skb); - return ret; + return res; } /* Caller must hold bond lock for read */ -static struct slave* -rlb_next_rx_slave(struct bonding *bond) +static struct slave *rlb_next_rx_slave(struct bonding *bond) { - struct slave *rx_slave = NULL, *slave = NULL; - unsigned int i = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct slave *rx_slave, *slave, *start_at; + int i = 0; - slave = bond_info->next_rx_slave; - if (slave == NULL) { - slave = bond->next; + if (bond_info->next_rx_slave) { + start_at = bond_info->next_rx_slave; + } else { + start_at = bond->first_slave; } - /* this loop uses the circular linked list property of the - * slave's list to go through all slaves - */ - for (i = 0; i < bond->slave_cnt; i++, slave = slave->next) { + rx_slave = NULL; + bond_for_each_slave_from(bond, slave, i, start_at) { if (SLAVE_IS_OK(slave)) { if (!rx_slave) { rx_slave = slave; - } - else if (slave->speed > rx_slave->speed) { + } else if (slave->speed > rx_slave->speed) { rx_slave = slave; } } @@ -464,48 +422,41 @@ /* teach the switch the mac of a disabled slave * on the primary for fault tolerance * - * Caller must hold bond->ptrlock for write or bond lock for write + * Caller must hold bond->curr_slave_lock for write or bond lock for write */ -static void -rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) +static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->current_slave) { + if (!bond->curr_active_slave) { return; } + if (!bond->alb_info.primary_is_promisc) { bond->alb_info.primary_is_promisc = 1; - dev_set_promiscuity(bond->current_slave->dev, 1); + dev_set_promiscuity(bond->curr_active_slave->dev, 1); } + bond->alb_info.rlb_promisc_timeout_counter = 0; - alb_send_learning_packets(bond->current_slave, addr); + alb_send_learning_packets(bond->curr_active_slave, addr); } /* slave being removed should not be active at this point * * Caller must hold bond lock for read */ -static void -rlb_clear_slave(struct bonding *bond, struct slave *slave) +static void rlb_clear_slave(struct bonding *bond, struct slave *slave) { - struct rlb_client_info *rx_hash_table = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; + struct rlb_client_info *rx_hash_table; u32 index, next_index; /* clear slave from rx_hashtbl */ _lock_rx_hashtbl(bond); - rx_hash_table = bond_info->rx_hashtbl; - - if (rx_hash_table == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; for (; index != RLB_NULL_INDEX; index = next_index) { next_index = rx_hash_table[index].next; - if (rx_hash_table[index].slave == slave) { struct slave *assigned_slave = rlb_next_rx_slave(bond); @@ -533,48 +484,63 @@ _unlock_rx_hashtbl(bond); - write_lock(&bond->ptrlock); - if (slave != bond->current_slave) { + write_lock(&bond->curr_slave_lock); + + if (slave != bond->curr_active_slave) { rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); } - write_unlock(&bond->ptrlock); + + write_unlock(&bond->curr_slave_lock); } -static void -rlb_update_client(struct rlb_client_info *client_info) +static void rlb_update_client(struct rlb_client_info *client_info) { - int i = 0; + int i; - if (client_info->slave == NULL) { + if (!client_info->slave) { return; } - for (i=0; iip_dst, - client_info->slave->dev, - client_info->ip_src, - client_info->mac_dst, - client_info->slave->dev->dev_addr, - client_info->mac_dst); + for (i = 0; i < RLB_ARP_BURST_SIZE; i++) { + struct sk_buff *skb; + + skb = arp_create(ARPOP_REPLY, ETH_P_ARP, + client_info->ip_dst, + client_info->slave->dev, + client_info->ip_src, + client_info->mac_dst, + client_info->slave->dev->dev_addr, + client_info->mac_dst); + if (!skb) { + printk(KERN_ERR DRV_NAME + ": Error: failed to create an ARP packet\n"); + continue; + } + + skb->dev = client_info->slave->dev; + + if (client_info->tag) { + skb = vlan_put_tag(skb, client_info->vlan_id); + if (!skb) { + printk(KERN_ERR DRV_NAME + ": Error: failed to insert VLAN tag\n"); + continue; + } + } + + arp_xmit(skb); } } /* sends ARP REPLIES that update the clients that need updating */ -static void -rlb_update_rx_clients(struct bonding *bond) +static void rlb_update_rx_clients(struct bonding *bond) { - u32 hash_index; - struct rlb_client_info *client_info = NULL; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -595,22 +561,15 @@ } /* The slave was assigned a new mac address - update the clients */ -static void -rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) +static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *slave) { - u32 hash_index; - u8 ntt = 0; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info* client_info = NULL; + struct rlb_client_info *client_info; + int ntt = 0; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -633,37 +592,31 @@ } /* mark all clients using src_ip to be updated */ -static void -rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) +static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip) { - u32 hash_index; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - struct rlb_client_info *client_info = NULL; + struct rlb_client_info *client_info; + u32 hash_index; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); if (!client_info->slave) { - printk(KERN_ERR "Bonding: Error: found a client with no" - " channel in the client's hash table\n"); + printk(KERN_ERR DRV_NAME + ": Error: found a client with no channel in " + "the client's hash table\n"); continue; } /*update all clients using this src_ip, that are not assigned - * to the team's address (current_slave) and have a known + * to the team's address (curr_active_slave) and have a known * unicast mac address. */ if ((client_info->ip_src == src_ip) && memcmp(client_info->slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN) && + bond->dev->dev_addr, ETH_ALEN) && memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond_info->rx_ntt = 1; @@ -674,30 +627,23 @@ } /* Caller must hold both bond and ptr locks for read */ -struct slave* -rlb_choose_channel(struct bonding *bond, struct arp_pkt *arp) +struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct rlb_client_info *client_info = NULL; + struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; + struct slave *assigned_slave; + struct rlb_client_info *client_info; u32 hash_index = 0; - struct slave *assigned_slave = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return NULL; - } - - hash_index = _simple_hash((u8 *)&arp->ip_dst, 4); + hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); - if (client_info->assigned == 1) { + if (client_info->assigned) { if ((client_info->ip_src == arp->ip_src) && (client_info->ip_dst == arp->ip_dst)) { /* the entry is already assigned to this client */ - if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) { /* update mac address from arp */ memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); @@ -710,12 +656,12 @@ } } else { /* the entry is already assigned to some other client, - * move the old client to primary (current_slave) so + * move the old client to primary (curr_active_slave) so * that the new client can be assigned to this entry. */ - if (bond->current_slave && - client_info->slave != bond->current_slave) { - client_info->slave = bond->current_slave; + if (bond->curr_active_slave && + client_info->slave != bond->curr_active_slave) { + client_info->slave = bond->curr_active_slave; rlb_update_client(client_info); } } @@ -736,11 +682,19 @@ if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) { client_info->ntt = 1; bond->alb_info.rx_ntt = 1; - } - else { + } else { client_info->ntt = 0; } + if (!list_empty(&bond->vlan_list)) { + unsigned short vlan_id; + int res = vlan_get_tag(skb, &vlan_id); + if (!res) { + client_info->tag = 1; + client_info->vlan_id = vlan_id; + } + } + if (!client_info->assigned) { u32 prev_tbl_head = bond_info->rx_hashtbl_head; bond_info->rx_hashtbl_head = hash_index; @@ -760,10 +714,9 @@ /* chooses (and returns) transmit channel for arp reply * does not choose channel for other arp types since they are - * sent on the current_slave + * sent on the curr_active_slave */ -static struct slave* -rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) +static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) { struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw; struct slave *tx_slave = NULL; @@ -772,19 +725,18 @@ /* the arp must be sent on the selected * rx channel */ - tx_slave = rlb_choose_channel(bond, arp); + tx_slave = rlb_choose_channel(skb, bond); if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - BOND_PRINT_DBG(("Server sent ARP Reply packet")); + dprintk("Server sent ARP Reply packet\n"); } else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) { - /* Create an entry in the rx_hashtbl for this client as a * place holder. * When the arp reply is received the entry will be updated * with the correct unicast address of the client. */ - rlb_choose_channel(bond, arp); + rlb_choose_channel(skb, bond); /* The ARP relpy packets must be delayed so that * they can cancel out the influence of the ARP request. @@ -797,34 +749,29 @@ * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - BOND_PRINT_DBG(("Server sent ARP Request packet")); + dprintk("Server sent ARP Request packet\n"); } return tx_slave; } /* Caller must hold bond lock for read */ -static void -rlb_rebalance(struct bonding *bond) +static void rlb_rebalance(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *assigned_slave = NULL; + struct slave *assigned_slave; + struct rlb_client_info *client_info; + int ntt; u32 hash_index; - struct rlb_client_info *client_info = NULL; - u8 ntt = 0; _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } - + ntt = 0; hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { client_info = &(bond_info->rx_hashtbl[hash_index]); assigned_slave = rlb_next_rx_slave(bond); - if (assigned_slave && (client_info->slave != assigned_slave)){ + if (assigned_slave && (client_info->slave != assigned_slave)) { client_info->slave = assigned_slave; client_info->ntt = 1; ntt = 1; @@ -839,97 +786,119 @@ } /* Caller must hold rx_hashtbl lock */ -static inline void -rlb_init_table_entry(struct rlb_client_info *entry) +static void rlb_init_table_entry(struct rlb_client_info *entry) { + memset(entry, 0, sizeof(struct rlb_client_info)); entry->next = RLB_NULL_INDEX; entry->prev = RLB_NULL_INDEX; - entry->assigned = 0; - entry->ntt = 0; } -static int -rlb_initialize(struct bonding *bond) +static int rlb_initialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type); + int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); int i; - size_t size; spin_lock_init(&(bond_info->rx_hashtbl_lock)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl != NULL) { - printk (KERN_ERR "%s: RLB hash table is not NULL\n", - bond->device->name); - _unlock_rx_hashtbl(bond); - return -1; - } - size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info); bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL); - if (bond_info->rx_hashtbl == NULL) { - printk (KERN_ERR "%s: Failed to allocate" - " RLB hash table\n", bond->device->name); + if (!bond_info->rx_hashtbl) { + printk(KERN_ERR DRV_NAME + ": Error: %s: Failed to allocate RLB hash table\n", + bond->dev->name); _unlock_rx_hashtbl(bond); return -1; } bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - for (i=0; irx_hashtbl + i); } - _unlock_rx_hashtbl(bond); - /* register to receive ARPs */ + _unlock_rx_hashtbl(bond); /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->device; + pk_type->dev = bond->dev; pk_type->func = rlb_arp_recv; pk_type->data = (void*)1; /* understand shared skbs */ + /* register to receive ARPs */ dev_add_pack(pk_type); return 0; } -static void -rlb_deinitialize(struct bonding *bond) +static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); dev_remove_pack(&(bond_info->rlb_pkt_type)); _lock_rx_hashtbl(bond); - if (bond_info->rx_hashtbl == NULL) { - _unlock_rx_hashtbl(bond); - return; - } + kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; + bond_info->rx_hashtbl_head = RLB_NULL_INDEX; + + _unlock_rx_hashtbl(bond); +} + +static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) +{ + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); + u32 curr_index; + + _lock_rx_hashtbl(bond); + + curr_index = bond_info->rx_hashtbl_head; + while (curr_index != RLB_NULL_INDEX) { + struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]); + u32 next_index = bond_info->rx_hashtbl[curr_index].next; + u32 prev_index = bond_info->rx_hashtbl[curr_index].prev; + + if (curr->tag && (curr->vlan_id == vlan_id)) { + if (curr_index == bond_info->rx_hashtbl_head) { + bond_info->rx_hashtbl_head = next_index; + } + if (prev_index != RLB_NULL_INDEX) { + bond_info->rx_hashtbl[prev_index].next = next_index; + } + if (next_index != RLB_NULL_INDEX) { + bond_info->rx_hashtbl[next_index].prev = prev_index; + } + + rlb_init_table_entry(curr); + } + + curr_index = next_index; + } + _unlock_rx_hashtbl(bond); } /*********************** tlb/rlb shared functions *********************/ -static void -alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) +static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) { - struct sk_buff *skb = NULL; + struct bonding *bond = bond_get_bond_by_slave(slave); struct learning_pkt pkt; - char *data = NULL; + int size = sizeof(struct learning_pkt); int i; - unsigned int size = sizeof(struct learning_pkt); memset(&pkt, 0, size); memcpy(pkt.mac_dst, mac_addr, ETH_ALEN); memcpy(pkt.mac_src, mac_addr, ETH_ALEN); pkt.type = __constant_htons(ETH_P_LOOP); - for (i=0; i < MAX_LP_RETRY; i++) { - skb = NULL; + for (i = 0; i < MAX_LP_BURST; i++) { + struct sk_buff *skb; + char *data; + skb = dev_alloc_skb(size); if (!skb) { return; @@ -937,28 +906,46 @@ data = skb_put(skb, size); memcpy(data, &pkt, size); + skb->mac.raw = data; skb->nh.raw = data + ETH_HLEN; skb->protocol = pkt.type; skb->priority = TC_PRIO_CONTROL; skb->dev = slave->dev; + + if (!list_empty(&bond->vlan_list)) { + struct vlan_entry *vlan; + + vlan = bond_next_vlan(bond, + bond->alb_info.current_alb_vlan); + + bond->alb_info.current_alb_vlan = vlan; + if (!vlan) { + kfree_skb(skb); + continue; + } + + skb = vlan_put_tag(skb, vlan->vlan_id); + if (!skb) { + printk(KERN_ERR DRV_NAME + ": Error: failed to insert VLAN tag\n"); + continue; + } + } + dev_queue_xmit(skb); } - } /* hw is a boolean parameter that determines whether we should try and * set the hw address of the device as well as the hw address of the * net_device */ -static int -alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) { - struct net_device *dev = NULL; + struct net_device *dev = slave->dev; struct sockaddr s_addr; - dev = slave->dev; - if (!hw) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; @@ -969,26 +956,23 @@ memcpy(s_addr.sa_data, addr, dev->addr_len); s_addr.sa_family = dev->type; if (dev->set_mac_address(dev, &s_addr)) { - printk(KERN_DEBUG "bonding: Error: alb_set_slave_mac_addr:" - " dev->set_mac_address of dev %s failed!" - " ALB mode requires that the base driver" - " support setting the hw address also when" - " the network device's interface is open\n", - dev->name); + printk(KERN_ERR DRV_NAME + ": Error: dev->set_mac_address of dev %s failed! ALB " + "mode requires that the base driver support setting " + "the hw address also when the network device's " + "interface is open\n", + dev->name); return -EOPNOTSUPP; } return 0; } -/* Caller must hold bond lock for write or ptrlock for write*/ -static void -alb_swap_mac_addr(struct bonding *bond, - struct slave *slave1, - struct slave *slave2) +/* Caller must hold bond lock for write or curr_slave_lock for write*/ +static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2) { - u8 tmp_mac_addr[ETH_ALEN]; struct slave *disabled_slave = NULL; - u8 slaves_state_differ; + u8 tmp_mac_addr[ETH_ALEN]; + int slaves_state_differ; slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); @@ -1005,8 +989,7 @@ */ rlb_req_update_slave_clients(bond, slave1); } - } - else { + } else { disabled_slave = slave1; } @@ -1018,15 +1001,14 @@ */ rlb_req_update_slave_clients(bond, slave2); } - } - else { + } else { disabled_slave = slave2; } if (bond->alb_info.rlb_enabled && slaves_state_differ) { - /* A disabled slave was assigned an active mac addr */ - rlb_teach_disabled_mac_on_primary(bond, - disabled_slave->dev->dev_addr); + /* A disabled slave was assigned an active mac addr */ + rlb_teach_disabled_mac_on_primary(bond, + disabled_slave->dev->dev_addr); } } @@ -1044,10 +1026,8 @@ * * Caller must hold bond lock */ -static void -alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) +static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave; int perm_curr_diff; int perm_bond_diff; @@ -1055,20 +1035,23 @@ slave->dev->dev_addr, ETH_ALEN); perm_bond_diff = memcmp(slave->perm_hwaddr, - bond->device->dev_addr, + bond->dev->dev_addr, ETH_ALEN); + if (perm_curr_diff && perm_bond_diff) { - tmp_slave = bond_get_first_slave(bond); - while (tmp_slave) { + struct slave *tmp_slave; + int i, found = 0; + + bond_for_each_slave(bond, tmp_slave, i) { if (!memcmp(slave->perm_hwaddr, - tmp_slave->dev->dev_addr, - ETH_ALEN)) { + tmp_slave->dev->dev_addr, + ETH_ALEN)) { + found = 1; break; } - tmp_slave = bond_get_next_slave(bond, tmp_slave); } - if (tmp_slave) { + if (found) { alb_swap_mac_addr(bond, slave, tmp_slave); } } @@ -1099,10 +1082,11 @@ * caller must hold the bond lock for write since the mac addresses are compared * and may be swapped. */ -static int -alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) +static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave) { - struct slave *tmp_slave1, *tmp_slave2; + struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave; + struct slave *has_bond_addr = bond->curr_active_slave; + int i, j, found = 0; if (bond->slave_cnt == 0) { /* this is the first slave */ @@ -1113,65 +1097,78 @@ * check uniqueness of slave's mac address against the other * slaves in the bond. */ - if (memcmp(slave->perm_hwaddr, bond->device->dev_addr, ETH_ALEN)) { - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { + if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave1, i) { if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr, ETH_ALEN)) { + found = 1; break; } } - if (tmp_slave1) { + + if (found) { /* a slave was found that is using the mac address * of the new slave */ - printk(KERN_ERR "bonding: Warning: the hw address " - "of slave %s is not unique - cannot enslave it!" - , slave->dev->name); + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is not " + "unique - cannot enslave it!", + slave->dev->name); return -EINVAL; } + return 0; } - /* the slave's address is equal to the address of the bond - * search for a spare address in the bond for this slave. + /* The slave's address is equal to the address of the bond. + * Search for a spare address in the bond for this slave. */ - tmp_slave1 = bond_get_first_slave(bond); - for (; tmp_slave1; tmp_slave1 = bond_get_next_slave(bond, tmp_slave1)) { - - tmp_slave2 = bond_get_first_slave(bond); - for (; tmp_slave2; tmp_slave2 = bond_get_next_slave(bond, tmp_slave2)) { + free_mac_slave = NULL; + bond_for_each_slave(bond, tmp_slave1, i) { + found = 0; + bond_for_each_slave(bond, tmp_slave2, j) { if (!memcmp(tmp_slave1->perm_hwaddr, tmp_slave2->dev->dev_addr, ETH_ALEN)) { - + found = 1; break; } } - if (!tmp_slave2) { + if (!found) { /* no slave has tmp_slave1's perm addr * as its curr addr */ + free_mac_slave = tmp_slave1; break; } + + if (!has_bond_addr) { + if (!memcmp(tmp_slave1->dev->dev_addr, + bond->dev->dev_addr, + ETH_ALEN)) { + + has_bond_addr = tmp_slave1; + } + } } - if (tmp_slave1) { - alb_set_slave_mac_addr(slave, tmp_slave1->perm_hwaddr, + if (free_mac_slave) { + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, bond->alb_info.rlb_enabled); - printk(KERN_WARNING "bonding: Warning: the hw address " - "of slave %s is in use by the bond; " - "giving it the hw address of %s\n", - slave->dev->name, tmp_slave1->dev->name); - } else { - printk(KERN_CRIT "bonding: Error: the hw address " - "of slave %s is in use by the bond; " - "couldn't find a slave with a free hw " - "address to give it (this should not have " - "happened)\n", slave->dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning: the hw address of slave %s is in use by " + "the bond; giving it the hw address of %s\n", + slave->dev->name, free_mac_slave->dev->name); + + } else if (has_bond_addr) { + printk(KERN_ERR DRV_NAME + ": Error: the hw address of slave %s is in use by the " + "bond; couldn't find a slave with a free hw address to " + "give it (this should not have happened)\n", + slave->dev->name); return -EFAULT; } @@ -1189,37 +1186,36 @@ * * For each slave, this function sets the interface to the new address and then * changes its dev_addr field to its previous value. - * + * * Unwinding assumes bond's mac address has not yet changed. */ -static inline int -alb_set_mac_address(struct bonding *bond, void *addr) +static int alb_set_mac_address(struct bonding *bond, void *addr) { struct sockaddr sa; - struct slave *slave; + struct slave *slave, *stop_at; char tmp_addr[ETH_ALEN]; - int error; + int res; + int i; if (bond->alb_info.rlb_enabled) { return 0; } - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + bond_for_each_slave(bond, slave, i) { if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; + res = -EOPNOTSUPP; goto unwind; } /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); - error = slave->dev->set_mac_address(slave->dev, addr); + res = slave->dev->set_mac_address(slave->dev, addr); /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (error) { + if (res) { goto unwind; } } @@ -1227,22 +1223,23 @@ return 0; unwind: - memcpy(sa.sa_data, bond->device->dev_addr, bond->device->addr_len); - sa.sa_family = bond->device->type; - slave = bond_get_first_slave(bond); - for (; slave; slave = bond_get_next_slave(bond, slave)) { + memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len); + sa.sa_family = bond->dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); slave->dev->set_mac_address(slave->dev, &sa); memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); } - return error; + return res; } /************************ exported alb funcions ************************/ -int -bond_alb_initialize(struct bonding *bond, int rlb_enabled) +int bond_alb_initialize(struct bonding *bond, int rlb_enabled) { int res; @@ -1264,8 +1261,7 @@ return 0; } -void -bond_alb_deinitialize(struct bonding *bond) +void bond_alb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1276,49 +1272,39 @@ } } -int -bond_alb_xmit(struct sk_buff *skb, struct net_device *dev) +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *eth_data = (struct ethhdr *)skb->data; + struct bonding *bond = bond_dev->priv; + struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - char do_tx_balance = 1; + static u32 ip_bcast = 0xffffffff; int hash_size = 0; + int do_tx_balance = 1; u32 hash_index = 0; u8 *hash_start = NULL; - u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; - - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } + int res = 1; - /* make sure that the current_slave and the slaves list do + /* make sure that the curr_active_slave and the slaves list do * not change during tx */ read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (!BOND_IS_OK(bond)) { + goto out; } - read_lock(&bond->ptrlock); - switch (ntohs(skb->protocol)) { case ETH_P_IP: if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) || - (skb->nh.iph->daddr == 0xffffffff)) { + (skb->nh.iph->daddr == ip_bcast)) { do_tx_balance = 0; break; } hash_start = (char*)&(skb->nh.iph->daddr); - hash_size = 4; + hash_size = sizeof(skb->nh.iph->daddr); break; - case ETH_P_IPV6: if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) { do_tx_balance = 0; @@ -1326,9 +1312,8 @@ } hash_start = (char*)&(skb->nh.ipv6h->daddr); - hash_size = 16; + hash_size = sizeof(skb->nh.ipv6h->daddr); break; - case ETH_P_IPX: if (skb->nh.ipxh->ipx_checksum != __constant_htons(IPX_NO_CHECKSUM)) { @@ -1337,8 +1322,7 @@ break; } - if (skb->nh.ipxh->ipx_type != - __constant_htons(IPX_TYPE_NCP)) { + if (skb->nh.ipxh->ipx_type != IPX_TYPE_NCP) { /* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism @@ -1350,14 +1334,12 @@ hash_start = (char*)eth_data->h_dest; hash_size = ETH_ALEN; break; - case ETH_P_ARP: do_tx_balance = 0; if (bond_info->rlb_enabled) { tx_slave = rlb_arp_xmit(skb, bond); } break; - default: do_tx_balance = 0; break; @@ -1370,43 +1352,50 @@ if (!tx_slave) { /* unbalanced or unassigned, send through primary */ - tx_slave = bond->current_slave; + tx_slave = bond->curr_active_slave; bond_info->unbalanced_load += skb->len; } if (tx_slave && SLAVE_IS_OK(tx_slave)) { - skb->dev = tx_slave->dev; - if (tx_slave != bond->current_slave) { + if (tx_slave != bond->curr_active_slave) { memcpy(eth_data->h_source, - tx_slave->dev->dev_addr, - ETH_ALEN); + tx_slave->dev->dev_addr, + ETH_ALEN); } - dev_queue_xmit(skb); + + res = bond_dev_queue_xmit(bond, skb, tx_slave->dev); } else { - /* no suitable interface, frame not sent */ if (tx_slave) { tlb_clear_slave(bond, tx_slave, 0); } - dev_kfree_skb(skb); } - read_unlock(&bond->ptrlock); +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } + read_unlock(&bond->curr_slave_lock); read_unlock(&bond->lock); return 0; } -void -bond_alb_monitor(struct bonding *bond) +void bond_alb_monitor(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - struct slave *slave = NULL; + struct slave *slave; + int i; read_lock(&bond->lock); - if ((bond->slave_cnt == 0) || !(bond->device->flags & IFF_UP)) { + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { bond_info->tx_rebalance_counter = 0; bond_info->lp_counter = 0; - goto out; + goto re_arm; } bond_info->tx_rebalance_counter++; @@ -1414,51 +1403,53 @@ /* send learning packets */ if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) { - /* change of current_slave involves swapping of mac addresses. + /* change of curr_active_slave involves swapping of mac addresses. * in order to avoid this swapping from happening while - * sending the learning packets, the ptrlock must be held for + * sending the learning packets, the curr_slave_lock must be held for * read. */ - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { alb_send_learning_packets(slave,slave->dev->dev_addr); - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); bond_info->lp_counter = 0; } /* rebalance tx traffic */ if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) { - read_lock(&bond->ptrlock); - slave = bond_get_first_slave(bond); - while (slave) { + + read_lock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { tlb_clear_slave(bond, slave, 1); - if (slave == bond->current_slave) { + if (slave == bond->curr_active_slave) { SLAVE_TLB_INFO(slave).load = bond_info->unbalanced_load / BOND_TLB_REBALANCE_INTERVAL; bond_info->unbalanced_load = 0; } - slave = bond_get_next_slave(bond, slave); } - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + bond_info->tx_rebalance_counter = 0; } /* handle rlb stuff */ if (bond_info->rlb_enabled) { /* the following code changes the promiscuity of the - * the current_slave. It needs to be locked with a + * the curr_active_slave. It needs to be locked with a * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + if (bond_info->primary_is_promisc && - (++bond_info->rlb_promisc_timeout_counter >= - RLB_PROMISC_TIMEOUT)) { + (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { bond_info->rlb_promisc_timeout_counter = 0; @@ -1466,12 +1457,13 @@ * because a slave was disabled then * it can now leave promiscuous mode. */ - dev_set_promiscuity(bond->current_slave->dev, -1); + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond_info->primary_is_promisc = 0; } - write_unlock(&bond->ptrlock); - if (bond_info->rlb_rebalance == 1) { + write_unlock(&bond->curr_slave_lock); + + if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; rlb_rebalance(bond); } @@ -1491,28 +1483,23 @@ } } +re_arm: + mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks); out: read_unlock(&bond->lock); - - if (bond->device->flags & IFF_UP) { - /* re-arm the timer */ - mod_timer(&(bond_info->alb_timer), - jiffies + (HZ/ALB_TIMER_TICKS_PER_SEC)); - } } -/* assumption: called before the slave is attched to the bond +/* assumption: called before the slave is attached to the bond * and not locked by the bond lock */ -int -bond_alb_init_slave(struct bonding *bond, struct slave *slave) +int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { - int err = 0; + int res; - err = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, bond->alb_info.rlb_enabled); - if (err) { - return err; + if (res) { + return res; } /* caller must hold the bond lock for write since the mac addresses @@ -1520,12 +1507,12 @@ */ write_lock_bh(&bond->lock); - err = alb_handle_addr_collision_on_attach(bond, slave); + res = alb_handle_addr_collision_on_attach(bond, slave); write_unlock_bh(&bond->lock); - if (err) { - return err; + if (res) { + return res; } tlb_init_slave(slave); @@ -1541,8 +1528,7 @@ } /* Caller must hold bond lock for write */ -void -bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) +void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) { if (bond->slave_cnt > 1) { alb_change_hw_addr_on_detach(bond, slave); @@ -1557,9 +1543,7 @@ } /* Caller must hold bond lock for read */ -void -bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, - char link) +void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); @@ -1583,112 +1567,126 @@ } /** - * bond_alb_assign_current_slave - assign new current_slave + * bond_alb_handle_active_change - assign new curr_active_slave * @bond: our bonding struct * @new_slave: new slave to assign * - * Set the bond->current_slave to @new_slave and handle + * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * - * Caller must hold bond ptrlock for write (or bond lock for write) + * Caller must hold bond curr_slave_lock for write (or bond lock for write) */ -void -bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave) +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave) { - struct slave *swap_slave = bond->current_slave; + struct slave *swap_slave; + int i; - if (bond->current_slave == new_slave) { + if (bond->curr_active_slave == new_slave) { return; } - if (bond->current_slave && bond->alb_info.primary_is_promisc) { - dev_set_promiscuity(bond->current_slave->dev, -1); + if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) { + dev_set_promiscuity(bond->curr_active_slave->dev, -1); bond->alb_info.primary_is_promisc = 0; bond->alb_info.rlb_promisc_timeout_counter = 0; } - bond->current_slave = new_slave; + swap_slave = bond->curr_active_slave; + bond->curr_active_slave = new_slave; if (!new_slave || (bond->slave_cnt == 0)) { return; } - /* set the new current_slave to the bonds mac address - * i.e. swap mac addresses of old current_slave and new current_slave + /* set the new curr_active_slave to the bonds mac address + * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave */ if (!swap_slave) { + struct slave *tmp_slave; /* find slave that is holding the bond's mac address */ - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, - bond->device->dev_addr, ETH_ALEN)) { + bond_for_each_slave(bond, tmp_slave, i) { + if (!memcmp(tmp_slave->dev->dev_addr, + bond->dev->dev_addr, ETH_ALEN)) { + swap_slave = tmp_slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } } - /* current_slave must be set before calling alb_swap_mac_addr */ + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->device->dev_addr, + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, bond->alb_info.rlb_enabled); /* fasten bond mac on new current slave */ - alb_send_learning_packets(new_slave, bond->device->dev_addr); + alb_send_learning_packets(new_slave, bond->dev->dev_addr); } } -int -bond_alb_set_mac_address(struct net_device *dev, void *addr) +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr; - struct slave *swap_slave = NULL; - int error = 0; + struct slave *slave, *swap_slave; + int res; + int i; if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - error = alb_set_mac_address(bond, addr); - if (error) { - return error; + res = alb_set_mac_address(bond, addr); + if (res) { + return res; } - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); - /* If there is no current_slave there is nothing else to do. + /* If there is no curr_active_slave there is nothing else to do. * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (bond->current_slave == NULL) { + if (!bond->curr_active_slave) { return 0; } - swap_slave = bond_get_first_slave(bond); - while (swap_slave) { - if (!memcmp(swap_slave->dev->dev_addr, dev->dev_addr, ETH_ALEN)) { + swap_slave = NULL; + + bond_for_each_slave(bond, slave, i) { + if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) { + swap_slave = slave; break; } - swap_slave = bond_get_next_slave(bond, swap_slave); } if (swap_slave) { - alb_swap_mac_addr(bond, swap_slave, bond->current_slave); + alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->current_slave, dev->dev_addr, + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, bond->alb_info.rlb_enabled); - alb_send_learning_packets(bond->current_slave, dev->dev_addr); + alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); if (bond->alb_info.rlb_enabled) { /* inform clients mac address has changed */ - rlb_req_update_slave_clients(bond, bond->current_slave); + rlb_req_update_slave_clients(bond, bond->curr_active_slave); } } return 0; } +void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id) +{ + if (bond->alb_info.current_alb_vlan && + (bond->alb_info.current_alb_vlan->vlan_id == vlan_id)) { + bond->alb_info.current_alb_vlan = NULL; + } + + if (bond->alb_info.rlb_enabled) { + rlb_clear_vlan(bond, vlan_id); + } +} + diff -urN linux-2.4.25/drivers/net/bonding/bond_alb.h linux-2.4.26/drivers/net/bonding/bond_alb.h --- linux-2.4.25/drivers/net/bonding/bond_alb.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/bonding/bond_alb.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + * Copyright(c) 1999 - 2004 Intel 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 @@ -24,6 +24,9 @@ * 2003/08/06 - Amir Noam * - Add support for setting bond's MAC address with special * handling required for ALB/TLB. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef __BOND_ALB_H__ @@ -74,6 +77,8 @@ u8 assigned; /* checking whether this entry is assigned */ u8 ntt; /* flag - need to transmit client info */ struct slave *slave; /* the slave assigned to this client */ + u8 tag; /* flag - need to tag skb */ + unsigned short vlan_id; /* VLAN tag associated with IP address */ }; struct tlb_slave_info { @@ -119,6 +124,7 @@ * rx traffic should be * rebalanced */ + struct vlan_entry *current_alb_vlan; }; int bond_alb_initialize(struct bonding *bond, int rlb_enabled); @@ -126,10 +132,10 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave); void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave); void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link); -void bond_alb_assign_current_slave(struct bonding *bond, struct slave *new_slave); -int bond_alb_xmit(struct sk_buff *skb, struct net_device *dev); +void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave); +int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev); void bond_alb_monitor(struct bonding *bond); -int bond_alb_set_mac_address(struct net_device *dev, void *addr); - +int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); +void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id); #endif /* __BOND_ALB_H__ */ diff -urN linux-2.4.25/drivers/net/bonding/bond_main.c linux-2.4.26/drivers/net/bonding/bond_main.c --- linux-2.4.25/drivers/net/bonding/bond_main.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/bonding/bond_main.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /* * originally based on the dummy device. * - * Copyright 1999, Thomas Davis, tadavis@lbl.gov. + * Copyright 1999, Thomas Davis, tadavis@lbl.gov. * Licensed under the GPL. Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver @@ -15,9 +15,9 @@ * * How it works: * ifconfig bond0 ipaddress netmask up - * will setup a network device, with an ip address. No mac address - * will be assigned at this time. The hw mac address will come from - * the first slave bonded to the channel. All slaves will then use + * will setup a network device, with an ip address. No mac address + * will be assigned at this time. The hw mac address will come from + * the first slave bonded to the channel. All slaves will then use * this hw mac address. * * ifconfig bond0 down @@ -26,7 +26,7 @@ * ifenslave bond0 eth0 * will attach eth0 to bond0 as a slave. eth0 hw mac address will either * a: be used as initial mac address - * b: if a hw mac address already is there, eth0's hw mac address + * b: if a hw mac address already is there, eth0's hw mac address * will then be set from bond0. * * v0.1 - first working version. @@ -93,14 +93,14 @@ * * 2001/4/5 - Chad N. Tindel * - Ported to 2.4 Kernel - * + * * 2001/5/2 - Jeffrey E. Mast * - When a device is detached from a bond, the slave device is no longer * left thinking that is has a master. * * 2001/5/16 - Jeffrey E. Mast - * - memset did not appropriately initialized the bond rw_locks. Used - * rwlock_init to initialize to unlocked state to prevent deadlock when + * - memset did not appropriately initialized the bond rw_locks. Used + * rwlock_init to initialize to unlocked state to prevent deadlock when * first attempting a lock * - Called SET_MODULE_OWNER for bond device * @@ -119,7 +119,7 @@ * * 2001/6/01 - Chad N. Tindel * - Added /proc support for getting bond and slave information. - * Information is in /proc/net//info. + * Information is in /proc/net//info. * - Changed the locking when calling bond_close to prevent deadlock. * * 2001/8/05 - Janice Girouard @@ -144,8 +144,8 @@ * but only for an up link. * * 2001/9/20 - Chad N. Tindel - * - Add the device field to bonding_t. Previously the net_device - * corresponding to a bond wasn't available from the bonding_t + * - Add the device field to bonding_t. Previously the net_device + * corresponding to a bond wasn't available from the bonding_t * structure. * * 2001/9/25 - Janice Girouard @@ -155,10 +155,10 @@ * - Various memory leak fixes * * 2001/11/5 - Mark Huth - * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under - * certain hotswap conditions. + * - Don't take rtnl lock in bond_mii_monitor as it deadlocks under + * certain hotswap conditions. * Note: this same change may be required in bond_arp_monitor ??? - * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr + * - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr * - Handle hot swap ethernet interface deregistration events to remove * kernel oops following hot swap of enslaved interface * @@ -222,23 +222,23 @@ * - fix deletion of multicast groups after unloading module * * 2002/11/06 - Kameshwara Rayaprolu - * - Changes to prevent panic from closing the device twice; if we close - * the device in bond_release, we must set the original_flags to down + * - Changes to prevent panic from closing the device twice; if we close + * the device in bond_release, we must set the original_flags to down * so it won't be closed again by the network layer. * * 2002/11/07 - Tony Cureington * - Fix arp_target_hw_addr memory leak - * - Created activebackup_arp_monitor function to handle arp monitoring - * in active backup mode - the bond_arp_monitor had several problems... - * such as allowing slaves to tx arps sequentially without any delay + * - Created activebackup_arp_monitor function to handle arp monitoring + * in active backup mode - the bond_arp_monitor had several problems... + * such as allowing slaves to tx arps sequentially without any delay * for a response * - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote * this function to just handle arp monitoring in load-balancing mode; * it is a lot more compact now - * - Changes to ensure one and only one slave transmits in active-backup + * - Changes to ensure one and only one slave transmits in active-backup * mode - * - Robustesize parameters; warn users about bad combinations of - * parameters; also if miimon is specified and a network driver does + * - Robustesize parameters; warn users about bad combinations of + * parameters; also if miimon is specified and a network driver does * not support MII or ETHTOOL, inform the user of this * - Changes to support link_failure_count when in arp monitoring mode * - Fix up/down delay reported in /proc @@ -248,7 +248,7 @@ * * 2002/11/16 - Laurent Deniel * - fix multicast handling in activebackup_arp_monitor - * - remove one unnecessary and confusing current_slave == slave test + * - remove one unnecessary and confusing curr_active_slave == slave test * in activebackup_arp_monitor * * 2002/11/17 - Laurent Deniel @@ -267,7 +267,7 @@ * One change: an invalid choice will cause module load failure, * rather than the previous behavior of just picking one. * - Minor cleanups; got rid of dup ctype stuff, atoi function - * + * * 2003/02/07 - Jay Vosburgh * - Added use_carrier module parameter that causes miimon to * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls. @@ -330,7 +330,7 @@ * new/old ifenslave and new/old bonding. * * 2003/05/01 - Shmulik Hen - * - Fixed bug in bond_release_all(): save old value of current_slave + * - Fixed bug in bond_release_all(): save old value of curr_active_slave * before setting it to NULL. * - Changed driver versioning scheme to include version number instead * of release date (that is already in another field). There are 3 @@ -358,7 +358,7 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. - * - Concentrate all assignments of current_slave to a single point + * - Concentrate all assignments of curr_active_slave to a single point * so specific modes can take actions when the primary adapter is * changed. * - Take the updelay parameter into consideration during bond_enslave @@ -426,8 +426,53 @@ * - Convert /proc to seq_file interface. * Change /proc/net/bondX/info to /proc/net/bonding/bondX. * Set version to 2.4.1. + * + * 2003/11/20 - Amir Noam + * - Fix /proc creation/destruction. + * + * 2003/12/01 - Shmulik Hen + * - Massive cleanup - Set version to 2.5.0 + * Code changes: + * o Consolidate format of prints and debug prints. + * o Remove bonding_t/slave_t typedefs and consolidate all casts. + * o Remove dead code and unnecessary checks. + * o Consolidate starting/stopping timers. + * o Consolidate handling of primary module param throughout the code. + * o Removed multicast module param support - all settings are done + * according to mode. + * o Slave list iteration - bond is no longer part of the list, + * added cyclic list iteration macros. + * o Consolidate error handling in all xmit functions. + * Style changes: + * o Consolidate function naming and declarations. + * o Consolidate function params and local variables names. + * o Consolidate return values. + * o Consolidate curly braces. + * o Consolidate conditionals format. + * o Change struct member names and types. + * o Chomp trailing spaces, remove empty lines, fix indentations. + * o Re-organize code according to context. + * + * 2003/12/30 - Amir Noam + * - Fixed: Cannot remove and re-enslave the original active slave. + * - Fixed: Releasing the original active slave causes mac address + * duplication. + * - Add support for slaves that use ethtool_ops. + * Set version to 2.5.3. + * + * 2004/01/05 - Amir Noam + * - Save bonding parameters per bond instead of using the global values. + * Set version to 2.5.4. + * + * 2004/01/14 - Shmulik Hen + * - Enhance VLAN support: + * * Add support for VLAN hardware acceleration capable slaves. + * * Add capability to tag self generated packets in ALB/TLB modes. + * Set version to 2.6.0. */ +//#define BONDING_DEBUG 1 + #include #include #include @@ -452,7 +497,6 @@ #include #include #include - #include #include #include @@ -461,58 +505,72 @@ #include #include #include - -#include #include #include #include #include #include +#include +#include #include "bonding.h" #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "2.4.1" -#define DRV_RELDATE "September 15, 2003" -#define DRV_NAME "bonding" -#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" - -static const char *version = -DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n"; +/*---------------------------- Module parameters ----------------------------*/ /* monitor all links that often (in milliseconds). <=0 disables monitoring */ -#ifndef BOND_LINK_MON_INTERV #define BOND_LINK_MON_INTERV 0 -#endif - -#ifndef BOND_LINK_ARP_INTERV #define BOND_LINK_ARP_INTERV 0 -#endif -#ifndef MAX_ARP_IP_TARGETS -#define MAX_ARP_IP_TARGETS 16 -#endif +static int max_bonds = BOND_DEFAULT_MAX_BONDS; +static int miimon = BOND_LINK_MON_INTERV; +static int updelay = 0; +static int downdelay = 0; +static int use_carrier = 1; +static char *mode = NULL; +static char *primary = NULL; +static char *lacp_rate = NULL; +static int arp_interval = BOND_LINK_ARP_INTERV; +static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; + +MODULE_PARM(max_bonds, "i"); +MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); +MODULE_PARM(miimon, "i"); +MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); +MODULE_PARM(updelay, "i"); +MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); +MODULE_PARM(downdelay, "i"); +MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); +MODULE_PARM(use_carrier, "i"); +MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); +MODULE_PARM(primary, "s"); +MODULE_PARM_DESC(primary, "Primary network device to use"); +MODULE_PARM(lacp_rate, "s"); +MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +MODULE_PARM(arp_interval, "i"); +MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); +MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(BOND_MAX_ARP_TARGETS) "s"); +MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -#define USES_PRIMARY(mode) \ - (((mode) == BOND_MODE_ACTIVEBACKUP) || \ - ((mode) == BOND_MODE_TLB) || \ - ((mode) == BOND_MODE_ALB)) +/*----------------------------- Global variables ----------------------------*/ -struct bond_parm_tbl { - char *modename; - int mode; -}; +static const char *version = + DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; -static int arp_interval = BOND_LINK_ARP_INTERV; -static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, }; -static u32 arp_target[MAX_ARP_IP_TARGETS] = { 0, } ; -static int arp_ip_count = 0; -static u32 my_ip = 0; -char *arp_target_hw_addr = NULL; +static LIST_HEAD(bond_dev_list); -static char *primary= NULL; +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *bond_proc_dir = NULL; +#endif -static int app_abi_ver = 0; +static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; +static int arp_ip_count = 0; +static u32 my_ip = 0; +static int bond_mode = BOND_MODE_ROUNDROBIN; +static int lacp_fast = 0; +static int app_abi_ver = 0; static int orig_app_abi_ver = -1; /* This is used to save the first ABI version * we receive from the application. Once set, * it won't be changed, and the module will @@ -521,14 +579,16 @@ * another ABI version. */ -static int max_bonds = BOND_DEFAULT_MAX_BONDS; -static int miimon = BOND_LINK_MON_INTERV; -static int use_carrier = 1; -static int bond_mode = BOND_MODE_ROUNDROBIN; -static int updelay = 0; -static int downdelay = 0; +struct bond_parm_tbl { + char *modename; + int mode; +}; -static char *mode = NULL; +static struct bond_parm_tbl bond_lacp_tbl[] = { +{ "slow", AD_LACP_SLOW}, +{ "fast", AD_LACP_FAST}, +{ NULL, -1}, +}; static struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, @@ -541,103 +601,15 @@ { NULL, -1}, }; -static int multicast_mode = BOND_MULTICAST_ALL; -static char *multicast = NULL; - -static struct bond_parm_tbl bond_mc_tbl[] = { -{ "disabled", BOND_MULTICAST_DISABLED}, -{ "active", BOND_MULTICAST_ACTIVE}, -{ "all", BOND_MULTICAST_ALL}, -{ NULL, -1}, -}; - -static int lacp_fast = 0; -static char *lacp_rate = NULL; - -static struct bond_parm_tbl bond_lacp_tbl[] = { -{ "slow", AD_LACP_SLOW}, -{ "fast", AD_LACP_FAST}, -{ NULL, -1}, -}; - -static LIST_HEAD(bond_dev_list); -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry *bond_proc_dir = NULL; -#endif +/*-------------------------- Forward declarations ---------------------------*/ -MODULE_PARM(max_bonds, "i"); -MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); -MODULE_PARM(miimon, "i"); -MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); -MODULE_PARM(use_carrier, "i"); -MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 0 for off, 1 for on (default)"); -MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); -MODULE_PARM(arp_interval, "i"); -MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); -MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); -MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -MODULE_PARM(updelay, "i"); -MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); -MODULE_PARM(downdelay, "i"); -MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); -MODULE_PARM(primary, "s"); -MODULE_PARM_DESC(primary, "Primary network device to use"); -MODULE_PARM(multicast, "s"); -MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)"); -MODULE_PARM(lacp_rate, "s"); -MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)"); +static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode); -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *bond_get_stats(struct net_device *dev); -static void bond_mii_monitor(struct net_device *dev); -static void loadbalance_arp_monitor(struct net_device *dev); -static void activebackup_arp_monitor(struct net_device *dev); -static void bond_mc_list_destroy(struct bonding *bond); -static void bond_mc_add(bonding_t *bond, void *addr, int alen); -static void bond_mc_delete(bonding_t *bond, void *addr, int alen); -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, int gpf_flag); -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2); -static void bond_set_promiscuity(bonding_t *bond, int inc); -static void bond_set_allmulti(bonding_t *bond, int inc); -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list); -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old); -static int bond_enslave(struct net_device *master, struct net_device *slave); -static int bond_release(struct net_device *master, struct net_device *slave); -static int bond_release_all(struct net_device *master); -static int bond_sethwaddr(struct net_device *master, struct net_device *slave); -static void change_active_interface(struct bonding *bond, struct slave *new); -static void reselect_active_interface(struct bonding *bond); -static struct slave *find_best_interface(struct bonding *bond); - - -/* #define BONDING_DEBUG 1 */ -#ifdef BONDING_DEBUG -#define dprintk(x...) printk(x...) -#else /* BONDING_DEBUG */ -#define dprintk(x...) do {} while (0) -#endif /* BONDING_DEBUG */ - -/* several macros */ - -static void arp_send_all(slave_t *slave) -{ - int i; - - for (i = 0; (idev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } -} - +/*---------------------------- General routines -----------------------------*/ -static const char * -bond_mode_name(void) +static const char *bond_mode_name(int mode) { - switch (bond_mode) { + switch (mode) { case BOND_MODE_ROUNDROBIN : return "load balancing (round-robin)"; case BOND_MODE_ACTIVEBACKUP : @@ -657,767 +629,1070 @@ } } -static const char * -multicast_mode_name(void) +/*---------------------------------- VLAN -----------------------------------*/ + +/** + * bond_add_vlan - add a new vlan id on bond + * @bond: bond that got the notification + * @vlan_id: the vlan id to add + * + * Returns -ENOMEM if allocation failed. + */ +static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) { - switch(multicast_mode) { - case BOND_MULTICAST_DISABLED : - return "disabled"; - case BOND_MULTICAST_ACTIVE : - return "active slave only"; - case BOND_MULTICAST_ALL : - return "all slaves"; - default : - return "unknown"; + struct vlan_entry *vlan; + + dprintk("bond: %s, vlan id %d\n", + (bond ? bond->dev->name: "None"), vlan_id); + + vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL); + if (!vlan) { + return -ENOMEM; } -} -void bond_set_slave_inactive_flags(slave_t *slave) -{ - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; -} + INIT_LIST_HEAD(&vlan->vlan_list); + vlan->vlan_id = vlan_id; -void bond_set_slave_active_flags(slave_t *slave) -{ - slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; + write_lock_bh(&bond->lock); + + list_add_tail(&vlan->vlan_list, &bond->vlan_list); + + write_unlock_bh(&bond->lock); + + dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); + + return 0; } -/* - * This function counts and verifies the the number of attached - * slaves, checking the count against the expected value (given that incr - * is either 1 or -1, for add or removal of a slave). Only - * bond_xmit_xor() uses the slave_cnt value, but this is still a good - * consistency check. +/** + * bond_del_vlan - delete a vlan id from bond + * @bond: bond that got the notification + * @vlan_id: the vlan id to delete + * + * returns -ENODEV if @vlan_id was not found in @bond. */ -static inline void -update_slave_cnt(bonding_t *bond, int incr) +static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) { - slave_t *slave = NULL; - int expect = bond->slave_cnt + incr; + struct vlan_entry *vlan, *next; + int res = -ENODEV; - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - bond->slave_cnt++; + dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); + + write_lock_bh(&bond->lock); + + list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) { + if (vlan->vlan_id == vlan_id) { + list_del(&vlan->vlan_list); + + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_clear_vlan(bond, vlan_id); + } + + dprintk("removed VLAN ID %d from bond %s\n", vlan_id, + bond->dev->name); + + kfree(vlan); + + if (list_empty(&bond->vlan_list) && + (bond->slave_cnt == 0)) { + /* Last VLAN removed and no slaves, so + * restore block on adding VLANs. This will + * be removed once new slaves that are not + * VLAN challenged will be added. + */ + bond->dev->features |= NETIF_F_VLAN_CHALLENGED; + } + + res = 0; + goto out; + } } - if (expect != bond->slave_cnt) - BUG(); + dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id, + bond->dev->name); + +out: + write_unlock_bh(&bond->lock); + return res; } -/* - * This function detaches the slave from the list . - * WARNING: no check is made to verify if the slave effectively - * belongs to . It returns in case it's needed. - * Nothing is freed on return, structures are just unchained. - * If the bond->current_slave pointer was pointing to , - * it should be changed by the calling function. +/** + * bond_has_challenged_slaves + * @bond: the bond we're working on * - * bond->lock held for writing by caller. + * Searches the slave list. Returns 1 if a vlan challenged slave + * was found, 0 otherwise. + * + * Assumes bond->lock is held. */ -static slave_t * -bond_detach_slave(bonding_t *bond, slave_t *slave) +static int bond_has_challenged_slaves(struct bonding *bond) { - if ((bond == NULL) || (slave == NULL) || - ((void *)bond == (void *)slave)) { - printk(KERN_ERR - "bond_detach_slave(): trying to detach " - "slave %p from bond %p\n", bond, slave); - return slave; - } - - if (bond->next == slave) { /* is the slave at the head ? */ - if (bond->prev == slave) { /* is the slave alone ? */ - bond->prev = bond->next = (slave_t *)bond; - } else { /* not alone */ - bond->next = slave->next; - slave->next->prev = (slave_t *)bond; - bond->prev->next = slave->next; - } - } else { - slave->prev->next = slave->next; - if (bond->prev == slave) { /* is this slave the last one ? */ - bond->prev = slave->prev; - } else { - slave->next->prev = slave->prev; + struct slave *slave; + int i; + + bond_for_each_slave(bond, slave, i) { + if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { + dprintk("found VLAN challenged slave - %s\n", + slave->dev->name); + return 1; } } - update_slave_cnt(bond, -1); - - return slave; + dprintk("no VLAN challenged slaves found\n"); + return 0; } -/* - * This function attaches the slave to the list . +/** + * bond_next_vlan - safely skip to the next item in the vlans list. + * @bond: the bond we're working on + * @curr: item we're advancing from * - * bond->lock held for writing by caller. + * Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL, + * or @curr->next otherwise (even if it is @curr itself again). + * + * Caller must hold bond->lock */ -static void -bond_attach_slave(struct bonding *bond, struct slave *new_slave) +struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) { - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; + struct vlan_entry *next, *last; - update_slave_cnt(bond, 1); -} + if (list_empty(&bond->vlan_list)) { + return NULL; + } + if (!curr) { + next = list_entry(bond->vlan_list.next, + struct vlan_entry, vlan_list); + } else { + last = list_entry(bond->vlan_list.prev, + struct vlan_entry, vlan_list); + if (last == curr) { + next = list_entry(bond->vlan_list.next, + struct vlan_entry, vlan_list); + } else { + next = list_entry(curr->vlan_list.next, + struct vlan_entry, vlan_list); + } + } -/* - * Less bad way to call ioctl from within the kernel; this needs to be - * done some other way to get the call out of interrupt context. - * Needs "ioctl" variable to be supplied by calling context. - */ -#define IOCTL(dev, arg, cmd) ({ \ - int ret; \ - mm_segment_t fs = get_fs(); \ - set_fs(get_ds()); \ - ret = ioctl(dev, arg, cmd); \ - set_fs(fs); \ - ret; }) + return next; +} -/* - * Get link speed and duplex from the slave's base driver - * using ethtool. If for some reason the call fails or the - * values are invalid, fake speed and duplex to 100/Full - * and return error. +/** + * bond_dev_queue_xmit - Prepare skb for xmit. + * + * @bond: bond device that got this skb for tx. + * @skb: hw accel VLAN tagged skb to transmit + * @slave_dev: slave that is supposed to xmit this skbuff + * + * When the bond gets an skb to tarnsmit that is + * already hardware accelerated VLAN tagged, and it + * needs to relay this skb to a slave that is not + * hw accel capable, the skb needs to be "unaccelerated", + * i.e. strip the hwaccel tag and re-insert it as part + * of the payload. + * + * Assumption - once a VLAN device is created over the bond device, all + * packets are going to be hardware accelerated VLAN tagged since the IP + * binding is done over the VLAN device */ -static int bond_update_speed_duplex(struct slave *slave) +int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) { - struct net_device *dev = slave->dev; - static int (* ioctl)(struct net_device *, struct ifreq *, int); - struct ifreq ifr; - struct ethtool_cmd etool; + unsigned short vlan_id; + int res; - ioctl = dev->do_ioctl; - if (ioctl) { - etool.cmd = ETHTOOL_GSET; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { - slave->speed = etool.speed; - slave->duplex = etool.duplex; - } else { - goto err_out; + if (!list_empty(&bond->vlan_list) && + !(slave_dev->features & NETIF_F_HW_VLAN_TX)) { + res = vlan_get_tag(skb, &vlan_id); + if (res) { + return -EINVAL; } - } else { - goto err_out; - } - switch (slave->speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - break; - default: - goto err_out; + skb->dev = slave_dev; + skb = vlan_put_tag(skb, vlan_id); + if (!skb) { + /* vlan_put_tag() frees the skb in case of error, + * so return success here so the calling functions + * won't attempt to free is again. + */ + return 0; + } + } else { + skb->dev = slave_dev; } - switch (slave->duplex) { - case DUPLEX_FULL: - case DUPLEX_HALF: - break; - default: - goto err_out; - } + skb->priority = 1; + dev_queue_xmit(skb); return 0; - -err_out: - /* Fake speed and duplex */ - slave->speed = SPEED_100; - slave->duplex = DUPLEX_FULL; - return -1; } -/* - * if supports MII link status reporting, check its link status. - * - * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), - * depening upon the setting of the use_carrier parameter. - * - * Return either BMSR_LSTATUS, meaning that the link is up (or we - * can't tell and just pretend it is), or 0, meaning that the link is - * down. - * - * If reporting is non-zero, instead of faking link up, return -1 if - * both ETHTOOL and MII ioctls fail (meaning the device does not - * support them). If use_carrier is set, return whatever it says. - * It'd be nice if there was a good way to tell if a driver supports - * netif_carrier, but there really isn't. +/* + * In the following 3 functions, bond_vlan_rx_register(), bond_vlan_rx_add_vid + * and bond_vlan_rx_kill_vid, We don't protect the slave list iteration with a + * lock because: + * a. This operation is performed in IOCTL context, + * b. The operation is protected by the RTNL semaphore in the 8021q code, + * c. Holding a lock with BH disabled while directly calling a base driver + * entry point is generally a BAD idea. + * + * The design of synchronization/protection for this operation in the 8021q + * module is good for one or more VLAN devices over a single physical device + * and cannot be extended for a teaming solution like bonding, so there is a + * potential race condition here where a net device from the vlan group might + * be referenced (either by a base driver or the 8021q code) while it is being + * removed from the system. However, it turns out we're not making matters + * worse, and if it works for regular VLAN usage it will work here too. +*/ + +/** + * bond_vlan_rx_register - Propagates registration to slaves + * @bond_dev: bonding net device that got called + * @grp: vlan group being registered */ -static int -bond_check_dev_link(struct net_device *dev, int reporting) +static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp) { - static int (* ioctl)(struct net_device *, struct ifreq *, int); - struct ifreq ifr; - struct mii_ioctl_data *mii; - struct ethtool_value etool; + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i; - if (use_carrier) { - return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + bond->vlgrp = grp; + + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; + + if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && + slave_dev->vlan_rx_register) { + slave_dev->vlan_rx_register(slave_dev, grp); + } } +} - ioctl = dev->do_ioctl; - if (ioctl) { - /* TODO: set pointer to correct ioctl on a per team member */ - /* bases to make this more efficient. that is, once */ - /* we determine the correct ioctl, we will always */ - /* call it and not the others for that team */ - /* member. */ +/** + * bond_vlan_rx_add_vid - Propagates adding an id to slaves + * @bond_dev: bonding net device that got called + * @vid: vlan id being added + */ +static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i, res; - /* - * We cannot assume that SIOCGMIIPHY will also read a - * register; not all network drivers (e.g., e100) - * support that. - */ + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; - /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ - mii = (struct mii_ioctl_data *)&ifr.ifr_data; - if (IOCTL(dev, &ifr, SIOCGMIIPHY) == 0) { - mii->reg_num = MII_BMSR; - if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) { - return mii->val_out & BMSR_LSTATUS; - } - } - - /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ - /* for a period of time so we attempt to get link status */ - /* from it last if the above MII ioctls fail... */ - etool.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (char*)&etool; - if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { - if (etool.data == 1) { - return BMSR_LSTATUS; - } else { -#ifdef BONDING_DEBUG - printk(KERN_INFO - ":: SIOCETHTOOL shows link down \n"); -#endif - return 0; - } + if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && + slave_dev->vlan_rx_add_vid) { + slave_dev->vlan_rx_add_vid(slave_dev, vid); } + } + res = bond_add_vlan(bond, vid); + if (res) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to add vlan id %d\n", + bond_dev->name, vid); } - - /* - * If reporting, report that either there's no dev->do_ioctl, - * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we - * cannot report link status). If not reporting, pretend - * we're ok. - */ - return reporting ? -1 : BMSR_LSTATUS; } -static u16 bond_check_mii_link(bonding_t *bond) +/** + * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves + * @bond_dev: bonding net device that got called + * @vid: vlan id being removed + */ +static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) { - int has_active_interface = 0; + struct bonding *bond = bond_dev->priv; + struct slave *slave; + struct net_device *vlan_dev; + int i, res; - read_lock_bh(&bond->lock); - read_lock(&bond->ptrlock); - has_active_interface = (bond->current_slave != NULL); - read_unlock(&bond->ptrlock); - read_unlock_bh(&bond->lock); + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; + + if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && + slave_dev->vlan_rx_kill_vid) { + /* Save and then restore vlan_dev in the grp array, + * since the slave's driver might clear it. + */ + vlan_dev = bond->vlgrp->vlan_devices[vid]; + slave_dev->vlan_rx_kill_vid(slave_dev, vid); + bond->vlgrp->vlan_devices[vid] = vlan_dev; + } + } - return (has_active_interface ? BMSR_LSTATUS : 0); + res = bond_del_vlan(bond, vid); + if (res) { + printk(KERN_ERR DRV_NAME + ": %s: Failed to remove vlan id %d\n", + bond_dev->name, vid); + } } -/* register to receive lacpdus on a bond */ -static void bond_register_lacpdu(struct bonding *bond) +static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) { - struct packet_type* pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); + struct vlan_entry *vlan; - /* initialize packet type */ - pk_type->type = PKT_TYPE_LACPDU; - pk_type->dev = bond->device; - pk_type->func = bond_3ad_lacpdu_recv; - pk_type->data = (void*)1; /* understand shared skbs */ + write_lock_bh(&bond->lock); - dev_add_pack(pk_type); + if (list_empty(&bond->vlan_list)) { + goto out; + } + + if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && + slave_dev->vlan_rx_register) { + slave_dev->vlan_rx_register(slave_dev, bond->vlgrp); + } + + if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || + !(slave_dev->vlan_rx_add_vid)) { + goto out; + } + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id); + } + +out: + write_unlock_bh(&bond->lock); } -/* unregister to receive lacpdus on a bond */ -static void bond_unregister_lacpdu(struct bonding *bond) +static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev) { - dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); + struct vlan_entry *vlan; + struct net_device *vlan_dev; + + write_lock_bh(&bond->lock); + + if (list_empty(&bond->vlan_list)) { + goto out; + } + + if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || + !(slave_dev->vlan_rx_kill_vid)) { + goto unreg; + } + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + /* Save and then restore vlan_dev in the grp array, + * since the slave's driver might clear it. + */ + vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id); + bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev; + } + +unreg: + if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && + slave_dev->vlan_rx_register) { + slave_dev->vlan_rx_register(slave_dev, NULL); + } + +out: + write_unlock_bh(&bond->lock); } -static int bond_open(struct net_device *dev) +/*------------------------------- Link status -------------------------------*/ + +/* + * Get link speed and duplex from the slave's base driver + * using ethtool. If for some reason the call fails or the + * values are invalid, fake speed and duplex to 100/Full + * and return error. + */ +static int bond_update_speed_duplex(struct slave *slave) { - struct bonding *bond = (struct bonding *)(dev->priv); - struct timer_list *timer = &((struct bonding *)(dev->priv))->mii_timer; - struct timer_list *arp_timer = &((struct bonding *)(dev->priv))->arp_timer; + struct net_device *slave_dev = slave->dev; + static int (* ioctl)(struct net_device *, struct ifreq *, int); + struct ifreq ifr; + struct ethtool_cmd etool; - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); + /* Fake speed and duplex */ + slave->speed = SPEED_100; + slave->duplex = DUPLEX_FULL; - /* bond_alb_initialize must be called before the timer - * is started. - */ - if (bond_alb_initialize(bond, (bond_mode == BOND_MODE_ALB))) { - /* something went wrong - fail the open operation */ + if (slave_dev->ethtool_ops) { + u32 res; + + if (!slave_dev->ethtool_ops->get_settings) { return -1; } - init_timer(alb_timer); - alb_timer->expires = jiffies + 1; - alb_timer->data = (unsigned long)bond; - alb_timer->function = (void *)&bond_alb_monitor; - add_timer(alb_timer); - } + res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool); + if (res < 0) { + return -1; + } - if (miimon > 0) { /* link check interval, in milliseconds. */ - init_timer(timer); - timer->expires = jiffies + (miimon * HZ / 1000); - timer->data = (unsigned long)dev; - timer->function = (void *)&bond_mii_monitor; - add_timer(timer); + goto verify; } - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - init_timer(arp_timer); - arp_timer->expires = jiffies + (arp_interval * HZ / 1000); - arp_timer->data = (unsigned long)dev; - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - arp_timer->function = (void *)&activebackup_arp_monitor; - } else { - arp_timer->function = (void *)&loadbalance_arp_monitor; - } - add_timer(arp_timer); + ioctl = slave_dev->do_ioctl; + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GSET; + ifr.ifr_data = (char*)&etool; + if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) { + return -1; + } + +verify: + switch (etool.speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + break; + default: + return -1; } - if (bond_mode == BOND_MODE_8023AD) { - struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); - init_timer(ad_timer); - ad_timer->expires = jiffies + (AD_TIMER_INTERVAL * HZ / 1000); - ad_timer->data = (unsigned long)bond; - ad_timer->function = (void *)&bond_3ad_state_machine_handler; - add_timer(ad_timer); - - /* register to receive LACPDUs */ - bond_register_lacpdu(bond); + switch (etool.duplex) { + case DUPLEX_FULL: + case DUPLEX_HALF: + break; + default: + return -1; } + slave->speed = etool.speed; + slave->duplex = etool.duplex; + return 0; } -static int bond_close(struct net_device *master) +/* + * if supports MII link status reporting, check its link status. + * + * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), + * depening upon the setting of the use_carrier parameter. + * + * Return either BMSR_LSTATUS, meaning that the link is up (or we + * can't tell and just pretend it is), or 0, meaning that the link is + * down. + * + * If reporting is non-zero, instead of faking link up, return -1 if + * both ETHTOOL and MII ioctls fail (meaning the device does not + * support them). If use_carrier is set, return whatever it says. + * It'd be nice if there was a good way to tell if a driver supports + * netif_carrier, but there really isn't. + */ +static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) { - bonding_t *bond = (struct bonding *) master->priv; - - write_lock_bh(&bond->lock); + static int (* ioctl)(struct net_device *, struct ifreq *, int); + struct ifreq ifr; + struct mii_ioctl_data *mii; + struct ethtool_value etool; - if (miimon > 0) { /* link check interval, in milliseconds. */ - del_timer(&bond->mii_timer); - } - if (arp_interval> 0) { /* arp interval, in milliseconds. */ - del_timer(&bond->arp_timer); - if (arp_target_hw_addr != NULL) { - kfree(arp_target_hw_addr); - arp_target_hw_addr = NULL; - } + if (bond->params.use_carrier) { + return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; } - if (bond_mode == BOND_MODE_8023AD) { - del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); + ioctl = slave_dev->do_ioctl; + if (ioctl) { + /* TODO: set pointer to correct ioctl on a per team member */ + /* bases to make this more efficient. that is, once */ + /* we determine the correct ioctl, we will always */ + /* call it and not the others for that team */ + /* member. */ - /* Unregister the receive of LACPDUs */ - bond_unregister_lacpdu(bond); - } + /* + * We cannot assume that SIOCGMIIPHY will also read a + * register; not all network drivers (e.g., e100) + * support that. + */ - bond_mc_list_destroy (bond); + /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + mii = (struct mii_ioctl_data *)&ifr.ifr_data; + if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { + mii->reg_num = MII_BMSR; + if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) { + return (mii->val_out & BMSR_LSTATUS); + } + } + } - write_unlock_bh(&bond->lock); + /* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */ + /* for a period of time so we attempt to get link status */ + /* from it last if the above MII ioctls fail... */ + if (slave_dev->ethtool_ops) { + if (slave_dev->ethtool_ops->get_link) { + u32 link; - /* Release the bonded slaves */ - bond_release_all(master); + link = slave_dev->ethtool_ops->get_link(slave_dev); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + return link ? BMSR_LSTATUS : 0; + } + } - bond_alb_deinitialize(bond); + if (ioctl) { + strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ); + etool.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (char*)&etool; + if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { + if (etool.data == 1) { + return BMSR_LSTATUS; + } else { + dprintk("SIOCETHTOOL shows link down\n"); + return 0; + } + } } - return 0; + /* + * If reporting, report that either there's no dev->do_ioctl, + * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we + * cannot report link status). If not reporting, pretend + * we're ok. + */ + return (reporting ? -1 : BMSR_LSTATUS); } -/* - * flush all members of flush->mc_list from device dev->mc_list +/*----------------------------- Multicast list ------------------------------*/ + +/* + * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise */ -static void bond_mc_list_flush(struct net_device *dev, struct net_device *flush) -{ - struct dev_mc_list *dmi; - - for (dmi = flush->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); +static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) +{ + return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && + dmi1->dmi_addrlen == dmi2->dmi_addrlen; +} - if (bond_mode == BOND_MODE_8023AD) { - /* del lacpdu mc addr from mc list */ - u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; +/* + * returns dmi entry if found, NULL otherwise + */ +static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list) +{ + struct dev_mc_list *idmi; - dev_mc_delete(dev, lacpdu_multicast, ETH_ALEN, 0); + for (idmi = mc_list; idmi; idmi = idmi->next) { + if (bond_is_dmi_same(dmi, idmi)) { + return idmi; + } } + + return NULL; } /* - * Totally destroys the mc_list in bond + * Push the promiscuity flag down to appropriate slaves */ -static void bond_mc_list_destroy(struct bonding *bond) +static void bond_set_promiscuity(struct bonding *bond, int inc) { - struct dev_mc_list *dmi; + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_promiscuity(bond->curr_active_slave->dev, inc); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_promiscuity(slave->dev, inc); + } + } +} - dmi = bond->mc_list; - while (dmi) { - bond->mc_list = dmi->next; - kfree(dmi); - dmi = bond->mc_list; +/* + * Push the allmulti flag down to all slaves + */ +static void bond_set_allmulti(struct bonding *bond, int inc) +{ + if (USES_PRIMARY(bond->params.mode)) { + /* write lock already acquired */ + if (bond->curr_active_slave) { + dev_set_allmulti(bond->curr_active_slave->dev, inc); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { + dev_set_allmulti(slave->dev, inc); + } } } /* - * Add a Multicast address to every slave in the bonding group + * Add a Multicast address to slaves + * according to mode */ -static void bond_mc_add(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : +static void bond_mc_add(struct bonding *bond, void *addr, int alen) +{ + if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_add(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) + if (bond->curr_active_slave) { + dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { dev_mc_add(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; + } } -} +} /* - * Remove a multicast address from every slave in the bonding group + * Remove a multicast address from slave + * according to mode */ -static void bond_mc_delete(bonding_t *bond, void *addr, int alen) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : +static void bond_mc_delete(struct bonding *bond, void *addr, int alen) +{ + if (USES_PRIMARY(bond->params.mode)) { /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_mc_delete(bond->current_slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) + if (bond->curr_active_slave) { + dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0); + } + } else { + struct slave *slave; + int i; + bond_for_each_slave(bond, slave, i) { dev_mc_delete(slave->dev, addr, alen, 0); - break; - case BOND_MULTICAST_DISABLED : - break; + } + } +} + +/* + * Totally destroys the mc_list in bond + */ +static void bond_mc_list_destroy(struct bonding *bond) +{ + struct dev_mc_list *dmi; + + dmi = bond->mc_list; + while (dmi) { + bond->mc_list = dmi->next; + kfree(dmi); + dmi = bond->mc_list; } -} +} /* * Copy all the Multicast addresses from src to the bonding device dst */ -static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, - int gpf_flag) +static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, int gpf_flag) { struct dev_mc_list *dmi, *new_dmi; - for (dmi = src; dmi != NULL; dmi = dmi->next) { + for (dmi = mc_list; dmi; dmi = dmi->next) { new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag); - if (new_dmi == NULL) { - return -ENOMEM; + if (!new_dmi) { + /* FIXME: Potential memory leak !!! */ + return -ENOMEM; } - new_dmi->next = dst->mc_list; - dst->mc_list = new_dmi; - - new_dmi->dmi_addrlen = dmi->dmi_addrlen; - memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); + new_dmi->next = bond->mc_list; + bond->mc_list = new_dmi; + new_dmi->dmi_addrlen = dmi->dmi_addrlen; + memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); new_dmi->dmi_users = dmi->dmi_users; - new_dmi->dmi_gusers = dmi->dmi_gusers; - } + new_dmi->dmi_gusers = dmi->dmi_gusers; + } + return 0; } /* - * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise - */ -static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2) -{ - return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 && - dmi1->dmi_addrlen == dmi2->dmi_addrlen; -} - -/* - * Push the promiscuity flag down to appropriate slaves + * flush all members of flush->mc_list from device dev->mc_list */ -static void bond_set_promiscuity(bonding_t *bond, int inc) -{ - slave_t *slave; - - if (USES_PRIMARY(bond_mode)) { - if (bond->current_slave) { - dev_set_promiscuity(bond->current_slave->dev, inc); - } +static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) +{ + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; - } else { - for (slave = bond->prev; slave != (slave_t*)bond; - slave = slave->prev) { - dev_set_promiscuity(slave->dev, inc); - } + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } -} -/* - * Push the allmulti flag down to all slaves - */ -static void bond_set_allmulti(bonding_t *bond, int inc) -{ - slave_t *slave; - switch (multicast_mode) { - case BOND_MULTICAST_ACTIVE : - /* write lock already acquired */ - if (bond->current_slave != NULL) - dev_set_allmulti(bond->current_slave->dev, inc); - break; - case BOND_MULTICAST_ALL : - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) - dev_set_allmulti(slave->dev, inc); - break; - case BOND_MULTICAST_DISABLED : - break; + if (bond->params.mode == BOND_MODE_8023AD) { + /* del lacpdu mc addr from mc list */ + u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; + + dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0); } -} +} + +/*--------------------------- Active slave change ---------------------------*/ -/* - * returns dmi entry if found, NULL otherwise +/* + * Update the mc list and multicast-related flags for the new and + * old active slaves (if any) according to the multicast mode, and + * promiscuous flags unconditionally. */ -static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, - struct dev_mc_list *mc_list) -{ - struct dev_mc_list *idmi; +static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active) +{ + struct dev_mc_list *dmi; + + if (!USES_PRIMARY(bond->params.mode)) { + /* nothing to do - mc list is already up-to-date on + * all slaves + */ + return; + } + + if (old_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(old_active->dev, -1); + } - for (idmi = mc_list; idmi != NULL; idmi = idmi->next) { - if (dmi_same(dmi, idmi)) { - return idmi; + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(old_active->dev, -1); + } + + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } } - return NULL; -} -static void set_multicast_list(struct net_device *master) + if (new_active) { + if (bond->dev->flags & IFF_PROMISC) { + dev_set_promiscuity(new_active->dev, 1); + } + + if (bond->dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(new_active->dev, 1); + } + + for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { + dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } + } +} + +/** + * find_best_interface - select the best available slave to be the active one + * @bond: our bonding struct + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static struct slave *bond_find_best_slave(struct bonding *bond) { - bonding_t *bond = master->priv; - struct dev_mc_list *dmi; + struct slave *new_active, *old_active; + struct slave *bestslave = NULL; + int mintime = bond->params.updelay; + int i; - write_lock_bh(&bond->lock); + new_active = old_active = bond->curr_active_slave; - /* - * Do promisc before checking multicast_mode + if (!new_active) { /* there were no active slaves left */ + if (bond->slave_cnt > 0) { /* found one slave */ + new_active = bond->first_slave; + } else { + return NULL; /* still no slave, return NULL */ + } + } + + /* first try the primary link; if arping, a link must tx/rx traffic + * before it can be considered the curr_active_slave - also, we would skip + * slaves between the curr_active_slave and primary_slave that may be up + * and able to arp */ - if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, 1); + if ((bond->primary_slave) && + (!bond->params.arp_interval) && + (IS_UP(bond->primary_slave->dev))) { + new_active = bond->primary_slave; + } - if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) - bond_set_promiscuity(bond, -1); + /* remember where to stop iterating over the slaves */ + old_active = new_active; - if (multicast_mode == BOND_MULTICAST_DISABLED) { - bond->flags = master->flags; - write_unlock_bh(&bond->lock); + bond_for_each_slave_from(bond, new_active, i, old_active) { + if (IS_UP(new_active->dev)) { + if (new_active->link == BOND_LINK_UP) { + return new_active; + } else if (new_active->link == BOND_LINK_BACK) { + /* link up, but waiting for stabilization */ + if (new_active->delay < mintime) { + mintime = new_active->delay; + bestslave = new_active; + } + } + } + } + + return bestslave; +} + +/** + * change_active_interface - change the active slave into the specified one + * @bond: our bonding struct + * @new: the new slave to make the active one + * + * Set the new slave to the bond's settings and unset them on the old + * curr_active_slave. + * Setting include flags, mc-list, promiscuity, allmulti, etc. + * + * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, + * because it is apparently the best available slave we have, even though its + * updelay hasn't timed out yet. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_change_active_slave(struct bonding *bond, struct slave *new_active) +{ + struct slave *old_active = bond->curr_active_slave; + + if (old_active == new_active) { return; } - /* set allmulti flag to slaves */ - if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, 1); + if (new_active) { + if (new_active->link == BOND_LINK_BACK) { + if (USES_PRIMARY(bond->params.mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one %d ms earlier.\n", + bond->dev->name, new_active->dev->name, + (bond->params.updelay - new_active->delay) * bond->params.miimon); + } + + new_active->delay = 0; + new_active->link = BOND_LINK_UP; + new_active->jiffies = jiffies; - if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) ) - bond_set_allmulti(bond, -1); + if (bond->params.mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(new_active, BOND_LINK_UP); + } - bond->flags = master->flags; + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); + } + } else { + if (USES_PRIMARY(bond->params.mode)) { + printk(KERN_INFO DRV_NAME + ": %s: making interface %s the new " + "active one.\n", + bond->dev->name, new_active->dev->name); + } + } + } - /* looking for addresses to add to slaves' mc list */ - for (dmi = master->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, bond->mc_list) == NULL) - bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); - } + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + if (old_active) { + bond_set_slave_inactive_flags(old_active); + } - /* looking for addresses to delete from slaves' list */ - for (dmi = bond->mc_list; dmi != NULL; dmi = dmi->next) { - if (bond_mc_list_find_dmi(dmi, master->mc_list) == NULL) - bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); + if (new_active) { + bond_set_slave_active_flags(new_active); + } } + if (USES_PRIMARY(bond->params.mode)) { + bond_mc_swap(bond, new_active, old_active); + } - /* save master's multicast list */ - bond_mc_list_destroy (bond); - bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC); + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_handle_active_change(bond, new_active); + } else { + bond->curr_active_slave = new_active; + } +} - write_unlock_bh(&bond->lock); +/** + * bond_select_active_slave - select a new active slave, if needed + * @bond: our bonding struct + * + * This functions shoud be called when one of the following occurs: + * - The old curr_active_slave has been released or lost its link. + * - The primary_slave has got its link back. + * - A slave has got its link back and there's no old curr_active_slave. + * + * Warning: Caller must hold curr_slave_lock for writing. + */ +static void bond_select_active_slave(struct bonding *bond) +{ + struct slave *best_slave; + + best_slave = bond_find_best_slave(bond); + if (best_slave != bond->curr_active_slave) { + bond_change_active_slave(bond, best_slave); + } } +/*--------------------------- slave list handling ---------------------------*/ + /* - * Update the mc list and multicast-related flags for the new and - * old active slaves (if any) according to the multicast mode, and - * promiscuous flags unconditionally. + * This function attaches the slave to the end of list. + * + * bond->lock held for writing by caller. */ -static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old) +static void bond_attach_slave(struct bonding *bond, struct slave *new_slave) { - struct dev_mc_list *dmi; + if (bond->first_slave == NULL) { /* attaching the first slave */ + new_slave->next = new_slave; + new_slave->prev = new_slave; + bond->first_slave = new_slave; + } else { + new_slave->next = bond->first_slave; + new_slave->prev = bond->first_slave->prev; + new_slave->next->prev = new_slave; + new_slave->prev->next = new_slave; + } - if (USES_PRIMARY(bond_mode)) { - if (bond->device->flags & IFF_PROMISC) { - if (old) - dev_set_promiscuity(old->dev, -1); - if (new) - dev_set_promiscuity(new->dev, 1); - } + bond->slave_cnt++; +} + +/* + * This function detaches the slave from the list. + * WARNING: no check is made to verify if the slave effectively + * belongs to . + * Nothing is freed on return, structures are just unchained. + * If any slave pointer in bond was pointing to , + * it should be changed by the calling function. + * + * bond->lock held for writing by caller. + */ +static void bond_detach_slave(struct bonding *bond, struct slave *slave) +{ + if (slave->next) { + slave->next->prev = slave->prev; } - switch(multicast_mode) { - case BOND_MULTICAST_ACTIVE : - if (bond->device->flags & IFF_ALLMULTI) { - if (old) - dev_set_allmulti(old->dev, -1); - if (new) - dev_set_allmulti(new->dev, 1); - } - /* first remove all mc addresses from old slave if any, - and _then_ add them to new active slave */ - if (old) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); - } - if (new) { - for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next) - dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + if (slave->prev) { + slave->prev->next = slave->next; + } + + if (bond->first_slave == slave) { /* slave is the first slave */ + if (bond->slave_cnt > 1) { /* there are more slave */ + bond->first_slave = slave->next; + } else { + bond->first_slave = NULL; /* slave was the last one */ } - break; - case BOND_MULTICAST_ALL : - /* nothing to do: mc list is already up-to-date on all slaves */ - break; - case BOND_MULTICAST_DISABLED : - break; } + + slave->next = NULL; + slave->prev = NULL; + bond->slave_cnt--; +} + +/*---------------------------------- IOCTL ----------------------------------*/ + +static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) +{ + dprintk("bond_dev=%p\n", bond_dev); + dprintk("slave_dev=%p\n", slave_dev); + dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); + return 0; } /* enslave device to bond device */ -static int bond_enslave(struct net_device *master_dev, - struct net_device *slave_dev) +static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond = NULL; - slave_t *new_slave = NULL; - unsigned long rflags = 0; - int err = 0; + struct bonding *bond = bond_dev->priv; + struct slave *new_slave = NULL; struct dev_mc_list *dmi; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; - int link_reporting; struct sockaddr addr; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } - bond = (struct bonding *) master_dev->priv; + int link_reporting; + int old_features = bond_dev->features; + int res = 0; if (slave_dev->do_ioctl == NULL) { - printk(KERN_DEBUG - "Warning : no link monitoring support for %s\n", - slave_dev->name); + printk(KERN_WARNING DRV_NAME + ": Warning : no link monitoring support for %s\n", + slave_dev->name); } - /* bond must be initialized by bond_open() before enslaving */ - if (!(master_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, master_dev is not up\n"); -#endif + if (!(bond_dev->flags & IFF_UP)) { + dprintk("Error, master_dev is not up\n"); return -EPERM; } /* already enslaved */ - if (master_dev->flags & IFF_SLAVE || slave_dev->flags & IFF_SLAVE) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, Device was already enslaved\n"); -#endif + if (slave_dev->flags & IFF_SLAVE) { + dprintk("Error, Device was already enslaved\n"); return -EBUSY; } + /* vlan challenged mutual exclusion */ + /* no need to lock since we're protected by rtnl_lock */ + if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { + dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + if (!list_empty(&bond->vlan_list)) { + printk(KERN_ERR DRV_NAME + ": Error: cannot enslave VLAN " + "challenged slave %s on VLAN enabled " + "bond %s\n", slave_dev->name, + bond_dev->name); + return -EPERM; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: enslaved VLAN challenged " + "slave %s. Adding VLANs will be blocked as " + "long as %s is part of bond %s\n", + slave_dev->name, slave_dev->name, + bond_dev->name); + bond_dev->features |= NETIF_F_VLAN_CHALLENGED; + } + } else { + dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + if (bond->slave_cnt == 0) { + /* First slave, and it is not VLAN challenged, + * so remove the block of adding VLANs over the bond. + */ + bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; + } + } + if (app_abi_ver >= 1) { /* The application is using an ABI, which requires the * slave interface to be closed. */ if ((slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is up\n"); -#endif - return -EPERM; + printk(KERN_ERR DRV_NAME + ": Error: %s is up\n", + slave_dev->name); + res = -EPERM; + goto err_undo_flags; } if (slave_dev->set_mac_address == NULL) { - printk(KERN_CRIT - "The slave device you specified does not support" - " setting the MAC address.\n"); - printk(KERN_CRIT - "Your kernel likely does not support slave" - " devices.\n"); + printk(KERN_ERR DRV_NAME + ": Error: The slave device you specified does " + "not support setting the MAC address.\n"); + printk(KERN_ERR + "Your kernel likely does not support slave " + "devices.\n"); - return -EOPNOTSUPP; + res = -EOPNOTSUPP; + goto err_undo_flags; } } else { /* The application is not using an ABI, which requires the * slave interface to be open. */ if (!(slave_dev->flags & IFF_UP)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error, slave_dev is not running\n"); -#endif - return -EINVAL; + printk(KERN_ERR DRV_NAME + ": Error: %s is not running\n", + slave_dev->name); + res = -EINVAL; + goto err_undo_flags; } - if ((bond_mode == BOND_MODE_8023AD) || - (bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - printk(KERN_ERR - "bonding: Error: to use %s mode, you must " - "upgrade ifenslave.\n", bond_mode_name()); - return -EOPNOTSUPP; + if ((bond->params.mode == BOND_MODE_8023AD) || + (bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + printk(KERN_ERR DRV_NAME + ": Error: to use %s mode, you must upgrade " + "ifenslave.\n", + bond_mode_name(bond->params.mode)); + res = -EOPNOTSUPP; + goto err_undo_flags; } } - if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { - return -ENOMEM; + new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); + if (!new_slave) { + res = -ENOMEM; + goto err_undo_flags; } - memset(new_slave, 0, sizeof(slave_t)); + + memset(new_slave, 0, sizeof(struct slave)); /* save slave's original flags before calling * netdev_set_master and dev_open @@ -1431,37 +1706,29 @@ */ memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); - if (bond->slave_cnt > 0) { - /* set slave to master's mac address - * The application already set the master's - * mac address to that of the first slave - */ - memcpy(addr.sa_data, master_dev->dev_addr, master_dev->addr_len); - addr.sa_family = slave_dev->type; - err = slave_dev->set_mac_address(slave_dev, &addr); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling set_mac_address\n", err); -#endif - goto err_free; - } + /* set slave to master's mac address + * The application already set the master's + * mac address to that of the first slave + */ + memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + addr.sa_family = slave_dev->type; + res = slave_dev->set_mac_address(slave_dev, &addr); + if (res) { + dprintk("Error %d calling set_mac_address\n", res); + goto err_free; } /* open the slave since the application closed it */ - err = dev_open(slave_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Openning slave %s failed\n", slave_dev->name); -#endif + res = dev_open(slave_dev); + if (res) { + dprintk("Openning slave %s failed\n", slave_dev->name); goto err_restore_mac; } } - err = netdev_set_master(slave_dev, master_dev); - if (err) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); -#endif + res = netdev_set_master(slave_dev, bond_dev); + if (res) { + dprintk("Error %d calling netdev_set_master\n", res); if (app_abi_ver < 1) { goto err_free; } else { @@ -1471,56 +1738,59 @@ new_slave->dev = slave_dev; - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ - err = bond_alb_init_slave(bond, new_slave); - if (err) { + res = bond_alb_init_slave(bond, new_slave); + if (res) { goto err_unset_master; } } - /* set promiscuity level to new slave */ - if (master_dev->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then the new slave gets the - * master's promisc (and mc) settings only if it becomes the - * current_slave, and that is taken care of later when calling - * bond_change_active() - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, 1); + /* If the mode USES_PRIMARY, then the new slave gets the + * master's promisc (and mc) settings only if it becomes the + * curr_active_slave, and that is taken care of later when calling + * bond_change_active() + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, 1); } - } - - if (multicast_mode == BOND_MULTICAST_ALL) { + /* set allmulti level to new slave */ - if (master_dev->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, 1); - - /* upload master's mc_list to new slave */ - for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, 1); + } + + /* upload master's mc_list to new slave */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); + } } - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { /* add lacpdu mc addr to mc list */ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; dev_mc_add(slave_dev, lacpdu_multicast, ETH_ALEN, 0); } + bond_add_vlans_on_slave(bond, slave_dev); + write_lock_bh(&bond->lock); - + bond_attach_slave(bond, new_slave); + new_slave->delay = 0; new_slave->link_failure_count = 0; - if (miimon > 0 && !use_carrier) { - link_reporting = bond_check_dev_link(slave_dev, 1); + if (bond->params.miimon && !bond->params.use_carrier) { + link_reporting = bond_check_dev_link(bond, slave_dev, 1); - if ((link_reporting == -1) && (arp_interval == 0)) { + if ((link_reporting == -1) && !bond->params.arp_interval) { /* * miimon is set but a bonded network driver * does not support ETHTOOL/MII and @@ -1529,157 +1799,136 @@ * here (because netif_carrier is always * supported); thus, we don't need to change * the messages for netif_carrier. - */ - printk(KERN_ERR - "bond_enslave(): MII and ETHTOOL support not " - "available for interface %s, and " - "arp_interval/arp_ip_target module parameters " - "not specified, thus bonding will not detect " - "link failures! see bonding.txt for details.\n", - slave_dev->name); + */ + printk(KERN_WARNING DRV_NAME + ": Warning: MII and ETHTOOL support not " + "available for interface %s, and " + "arp_interval/arp_ip_target module parameters " + "not specified, thus bonding will not detect " + "link failures! see bonding.txt for details.\n", + slave_dev->name); } else if (link_reporting == -1) { - /* unable get link status using mii/ethtool */ - printk(KERN_WARNING - "bond_enslave: can't get link status from " + /* unable get link status using mii/ethtool */ + printk(KERN_WARNING DRV_NAME + ": Warning: can't get link status from " "interface %s; the network driver associated " - "with this interface does not support " - "MII or ETHTOOL link status reporting, thus " - "miimon has no effect on this interface.\n", + "with this interface does not support MII or " + "ETHTOOL link status reporting, thus miimon " + "has no effect on this interface.\n", slave_dev->name); } } /* check for initial state */ - if ((miimon <= 0) || - (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) { - if (updelay) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " - "BOND_LINK_BACK\n"); -#endif + if (!bond->params.miimon || + (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) { + if (bond->params.updelay) { + dprintk("Initial state of slave_dev is " + "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; - new_slave->delay = updelay; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "Initial state of slave_dev is " + new_slave->delay = bond->params.updelay; + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_UP\n"); -#endif new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "Initial state of slave_dev is " + } else { + dprintk("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); -#endif new_slave->link = BOND_LINK_DOWN; } if (bond_update_speed_duplex(new_slave) && (new_slave->link != BOND_LINK_DOWN)) { - - printk(KERN_WARNING - "bond_enslave(): failed to get speed/duplex from %s, " - "speed forced to 100Mbps, duplex forced to Full.\n", + printk(KERN_WARNING DRV_NAME + ": Warning: failed to get speed/duplex from %s, speed " + "forced to 100Mbps, duplex forced to Full.\n", new_slave->dev->name); - if (bond_mode == BOND_MODE_8023AD) { + + if (bond->params.mode == BOND_MODE_8023AD) { printk(KERN_WARNING - "Operation of 802.3ad mode requires ETHTOOL support " - "in base driver for proper aggregator selection.\n"); + "Operation of 802.3ad mode requires ETHTOOL " + "support in base driver for proper aggregator " + "selection.\n"); } } - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that current_slave always point to the last - * usable interface, we just have to verify this interface's flag. - */ - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (((bond->current_slave == NULL) - || (bond->current_slave->dev->flags & IFF_NOARP)) - && (new_slave->link != BOND_LINK_DOWN)) { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is the first active slave\n"); -#endif + if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { + /* if there is a primary slave, remember it */ + if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { + bond->primary_slave = new_slave; + } + } + + switch (bond->params.mode) { + case BOND_MODE_ACTIVEBACKUP: + /* if we're in active-backup mode, we need one and only one active + * interface. The backup interfaces will have their NOARP flag set + * because we need them to be completely deaf and not to respond to + * any ARP request on the network to avoid fooling a switch. Thus, + * since we guarantee that curr_active_slave always point to the last + * usable interface, we just have to verify this interface's flag. + */ + if (((!bond->curr_active_slave) || + (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (new_slave->link != BOND_LINK_DOWN)) { + dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); - } - else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This is just a backup slave\n"); -#endif + bond_change_active_slave(bond, new_slave); + } else { + dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); } - if (((struct in_device *)slave_dev->ip_ptr) != NULL) { - read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list); - ifa = *ifap; - if (ifa != NULL) - my_ip = ifa->ifa_address; - read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags); - } - - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else if (bond_mode == BOND_MODE_8023AD) { + break; + case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism * will activate the slaves in the selected * aggregator */ bond_set_slave_inactive_flags(new_slave); /* if this is the first slave */ - if (new_slave == bond->next) { + if (bond->slave_cnt == 1) { SLAVE_AD_INFO(new_slave).id = 1; /* Initialize AD with the number of times that the AD timer is called in 1 second * can be called only after the mac address of the bond is set */ bond_3ad_initialize(bond, 1000/AD_TIMER_INTERVAL, - lacp_fast); + bond->params.lacp_fast); } else { SLAVE_AD_INFO(new_slave).id = - SLAVE_AD_INFO(new_slave->prev).id + 1; + SLAVE_AD_INFO(new_slave->prev).id + 1; } bond_3ad_bind_slave(new_slave); - } else if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: new_slave->state = BOND_STATE_ACTIVE; - if ((bond->current_slave == NULL) && (new_slave->link != BOND_LINK_DOWN)) { + if ((!bond->curr_active_slave) && + (new_slave->link != BOND_LINK_DOWN)) { /* first slave or no active slave yet, and this link * is OK, so make this interface the active one */ - change_active_interface(bond, new_slave); + bond_change_active_slave(bond, new_slave); } + break; + default: + dprintk("This slave is always active in trunk mode\n"); - /* if there is a primary slave, remember it */ - if (primary != NULL) { - if (strcmp(primary, new_slave->dev->name) == 0) { - bond->primary_slave = new_slave; - } - } - } else { -#ifdef BONDING_DEBUG - printk(KERN_CRIT "This slave is always active in trunk mode\n"); -#endif /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; - /* In trunking mode there is little meaning to current_slave + /* In trunking mode there is little meaning to curr_active_slave * anyway (it holds no special properties of the bond device), * so we can change it without calling change_active_interface() */ - if (bond->current_slave == NULL) - bond->current_slave = new_slave; - } + if (!bond->curr_active_slave) { + bond->curr_active_slave = new_slave; + } + break; + } /* switch(bond_mode) */ write_unlock_bh(&bond->lock); @@ -1693,38 +1942,34 @@ */ int ndx = 0; - for (ndx = 0; ndx < slave_dev->addr_len; ndx++) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Checking ndx=%d of master_dev->dev_addr\n", ndx); -#endif - if (master_dev->dev_addr[ndx] != 0) { -#ifdef BONDING_DEBUG - printk(KERN_DEBUG - "Found non-zero byte at ndx=%d\n", ndx); -#endif + for (ndx = 0; ndx < bond_dev->addr_len; ndx++) { + dprintk("Checking ndx=%d of bond_dev->dev_addr\n", + ndx); + if (bond_dev->dev_addr[ndx] != 0) { + dprintk("Found non-zero byte at ndx=%d\n", + ndx); break; } } - if (ndx == slave_dev->addr_len) { + + if (ndx == bond_dev->addr_len) { /* * We got all the way through the address and it was * all 0's. */ -#ifdef BONDING_DEBUG - printk(KERN_DEBUG "%s doesn't have a MAC address yet. ", - master_dev->name); - printk(KERN_DEBUG "Going to give assign it from %s.\n", - slave_dev->name); -#endif - bond_sethwaddr(master_dev, slave_dev); + dprintk("%s doesn't have a MAC address yet. \n", + bond_dev->name); + dprintk("Going to give assign it from %s.\n", + slave_dev->name); + bond_sethwaddr(bond_dev, slave_dev); } } - printk (KERN_INFO "%s: enslaving %s as a%s interface with a%s link.\n", - master_dev->name, slave_dev->name, - new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", - new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); + printk(KERN_INFO DRV_NAME + ": %s: enslaving %s as a%s interface with a%s link.\n", + bond_dev->name, slave_dev->name, + new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", + new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); /* enslave is successful */ return 0; @@ -1743,435 +1988,235 @@ err_free: kfree(new_slave); - return err; + +err_undo_flags: + bond_dev->features = old_features; + + return res; } -/* - * This function changes the active slave to slave . - * It returns -EINVAL in the following cases. - * - is not found in the list. - * - There is not active slave now. - * - is already active. - * - The link state of is not BOND_LINK_UP. - * - is not running. - * In these cases, this fuction does nothing. - * In the other cases, currnt_slave pointer is changed and 0 is returned. +/* + * Try to release the slave device from the bond device + * It is legal to access curr_active_slave without a lock because all the function + * is write-locked. + * + * The rules for slave state should be: + * for Active/Backup: + * Active stays on all backups go down + * for Bonded connections: + * The first up interface should be left on and all others downed. */ -static int bond_change_active(struct net_device *master_dev, struct net_device *slave_dev) +static int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond; - slave_t *slave; - slave_t *oldactive = NULL; - slave_t *newactive = NULL; - int ret = 0; - - if (master_dev == NULL || slave_dev == NULL) { - return -ENODEV; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; + struct sockaddr addr; + int mac_addr_differ; - /* Verify that master_dev is indeed the master of slave_dev */ + /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || - (slave_dev->master != master_dev)) { - + (slave_dev->master != bond_dev)) { + printk(KERN_ERR DRV_NAME + ": Error: %s: cannot release %s.\n", + bond_dev->name, slave_dev->name); return -EINVAL; } - bond = (struct bonding *) master_dev->priv; write_lock_bh(&bond->lock); - slave = (slave_t *)bond; - oldactive = bond->current_slave; - - while ((slave = slave->prev) != (slave_t *)bond) { - if(slave_dev == slave->dev) { - newactive = slave; - break; - } - } - /* - * Changing to the current active: do nothing; return success. - */ - if (newactive && (newactive == oldactive)) { - write_unlock_bh(&bond->lock); - return 0; + slave = bond_get_slave_by_dev(bond, slave_dev); + if (!slave) { + /* not a slave of this bond */ + printk(KERN_INFO DRV_NAME + ": %s: %s not enslaved\n", + bond_dev->name, slave_dev->name); + return -EINVAL; } - if ((newactive != NULL)&& - (oldactive != NULL)&& - (newactive->link == BOND_LINK_UP)&& - IS_UP(newactive->dev)) { - change_active_interface(bond, newactive); - } else { - ret = -EINVAL; + mac_addr_differ = memcmp(bond_dev->dev_addr, + slave->perm_hwaddr, + ETH_ALEN); + if (!mac_addr_differ && (bond->slave_cnt > 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: the permanent HWaddr of %s " + "- %02X:%02X:%02X:%02X:%02X:%02X - is " + "still in use by %s. Set the HWaddr of " + "%s to a different address to avoid " + "conflicts.\n", + slave_dev->name, + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5], + bond_dev->name, + slave_dev->name); + } + + /* Inform AD package of unbinding of slave. */ + if (bond->params.mode == BOND_MODE_8023AD) { + /* must be called before the slave is + * detached from the list + */ + bond_3ad_unbind_slave(slave); } - write_unlock_bh(&bond->lock); - return ret; -} -/** - * find_best_interface - select the best available slave to be the active one - * @bond: our bonding struct - * - * Warning: Caller must hold ptrlock for writing. - */ -static struct slave *find_best_interface(struct bonding *bond) -{ - struct slave *newslave, *oldslave; - struct slave *bestslave = NULL; - int mintime; + printk(KERN_INFO DRV_NAME + ": %s: releasing %s interface %s\n", + bond_dev->name, + (slave->state == BOND_STATE_ACTIVE) + ? "active" : "backup", + slave_dev->name); - newslave = oldslave = bond->current_slave; + oldcurrent = bond->curr_active_slave; - if (newslave == NULL) { /* there were no active slaves left */ - if (bond->next != (slave_t *)bond) { /* found one slave */ - newslave = bond->next; - } else { - return NULL; /* still no slave, return NULL */ - } - } + bond->current_arp_slave = NULL; - mintime = updelay; + /* release the slave from its bond */ + bond_detach_slave(bond, slave); - /* first try the primary link; if arping, a link must tx/rx traffic - * before it can be considered the current_slave - also, we would skip - * slaves between the current_slave and primary_slave that may be up - * and able to arp - */ - if ((bond->primary_slave != NULL) && (arp_interval == 0)) { - if (IS_UP(bond->primary_slave->dev)) - newslave = bond->primary_slave; + if (bond->primary_slave == slave) { + bond->primary_slave = NULL; } - /* remember where to stop iterating over the slaves */ - oldslave = newslave; - - do { - if (IS_UP(newslave->dev)) { - if (newslave->link == BOND_LINK_UP) { - return newslave; - } - else if (newslave->link == BOND_LINK_BACK) { - /* link up, but waiting for stabilization */ - if (newslave->delay < mintime) { - mintime = newslave->delay; - bestslave = newslave; - } - } - } - } while ((newslave = newslave->next) != oldslave); - - return bestslave; -} - -/** - * change_active_interface - change the active slave into the specified one - * @bond: our bonding struct - * @new: the new slave to make the active one - * - * Set the new slave to the bond's settings and unset them on the old - * current_slave. - * Setting include flags, mc-list, promiscuity, allmulti, etc. - * - * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, - * because it is apparently the best available slave we have, even though its - * updelay hasn't timed out yet. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void change_active_interface(struct bonding *bond, struct slave *new) -{ - struct slave *old = bond->current_slave; - - if (old == new) { - return; + if (oldcurrent == slave) { + bond_change_active_slave(bond, NULL); } - if (new) { - if (new->link == BOND_LINK_BACK) { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new " - "active one %d ms earlier.\n", - bond->device->name, new->dev->name, - (updelay - new->delay) * miimon); - } - - new->delay = 0; - new->link = BOND_LINK_UP; - new->jiffies = jiffies; - - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_handle_link_change(new, BOND_LINK_UP); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_handle_link_change(bond, new, BOND_LINK_UP); - } - } else { - if (USES_PRIMARY(bond_mode)) { - printk (KERN_INFO - "%s: making interface %s the new active one.\n", - bond->device->name, new->dev->name); - } - } + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + /* Must be called only after the slave has been + * detached from the list and the curr_active_slave + * has been cleared (if our_slave == old_current), + * but before a new active slave is selected. + */ + bond_alb_deinit_slave(bond, slave); } - if (bond_mode == BOND_MODE_ACTIVEBACKUP) { - if (old) { - bond_set_slave_inactive_flags(old); - } + if (oldcurrent == slave) { + bond_select_active_slave(bond); - if (new) { - bond_set_slave_active_flags(new); + if (!bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } } - if (USES_PRIMARY(bond_mode)) { - bond_mc_update(bond, new, old); - } - - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_assign_current_slave(bond, new); - } else { - bond->current_slave = new; - } -} - -/** - * reselect_active_interface - select a new active slave, if needed - * @bond: our bonding struct - * - * This functions shoud be called when one of the following occurs: - * - The old current_slave has been released or lost its link. - * - The primary_slave has got its link back. - * - A slave has got its link back and there's no old current_slave. - * - * Warning: Caller must hold ptrlock for writing. - */ -static void reselect_active_interface(struct bonding *bond) -{ - struct slave *best_slave; - - best_slave = find_best_interface(bond); - - if (best_slave != bond->current_slave) { - change_active_interface(bond, best_slave); - } -} - -/* - * Try to release the slave device from the bond device - * It is legal to access current_slave without a lock because all the function - * is write-locked. - * - * The rules for slave state should be: - * for Active/Backup: - * Active stays on all backups go down - * for Bonded connections: - * The first up interface should be left on and all others downed. - */ -static int bond_release(struct net_device *master, struct net_device *slave) -{ - bonding_t *bond; - slave_t *our_slave, *old_current; - struct sockaddr addr; - - if (master == NULL || slave == NULL) { - return -ENODEV; - } - - bond = (struct bonding *) master->priv; + if (bond->slave_cnt == 0) { + /* if the last slave was removed, zero the mac address + * of the master so it will be set by the application + * to the mac address of the first slave + */ + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); - /* master already enslaved, or slave not enslaved, - or no slave for this master */ - if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { - printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); - return -EINVAL; + if (list_empty(&bond->vlan_list)) { + bond_dev->features |= NETIF_F_VLAN_CHALLENGED; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: clearing HW address of %s while it " + "still has VLANs.\n", + bond_dev->name); + printk(KERN_WARNING DRV_NAME + ": When re-adding slaves, make sure the bond's " + "HW address matches its VLANs'.\n"); + } + } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) && + !bond_has_challenged_slaves(bond)) { + printk(KERN_INFO DRV_NAME + ": last VLAN challenged slave %s " + "left bond %s. VLAN blocking is removed\n", + slave_dev->name, bond_dev->name); + bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED; } - write_lock_bh(&bond->lock); - bond->current_arp_slave = NULL; - our_slave = (slave_t *)bond; - old_current = bond->current_slave; - while ((our_slave = our_slave->prev) != (slave_t *)bond) { - if (our_slave->dev == slave) { - int mac_addr_differ = memcmp(bond->device->dev_addr, - our_slave->perm_hwaddr, - ETH_ALEN); - if (!mac_addr_differ && (bond->slave_cnt > 1)) { - printk(KERN_WARNING "WARNING: the permanent HWaddr of %s " - "- %02X:%02X:%02X:%02X:%02X:%02X - " - "is still in use by %s. Set the HWaddr " - "of %s to a different address " - "to avoid conflicts.\n", - slave->name, - our_slave->perm_hwaddr[0], - our_slave->perm_hwaddr[1], - our_slave->perm_hwaddr[2], - our_slave->perm_hwaddr[3], - our_slave->perm_hwaddr[4], - our_slave->perm_hwaddr[5], - bond->device->name, - slave->name); - } - - /* Inform AD package of unbinding of slave. */ - if (bond_mode == BOND_MODE_8023AD) { - /* must be called before the slave is - * detached from the list - */ - bond_3ad_unbind_slave(our_slave); - } - - printk (KERN_INFO "%s: releasing %s interface %s\n", - master->name, - (our_slave->state == BOND_STATE_ACTIVE) ? "active" : "backup", - slave->name); - - /* release the slave from its bond */ - bond_detach_slave(bond, our_slave); - - if (bond->primary_slave == our_slave) { - bond->primary_slave = NULL; - } - - if (bond->current_slave == our_slave) { - change_active_interface(bond, NULL); - reselect_active_interface(bond); - } - - if (bond->current_slave == NULL) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); - } + write_unlock_bh(&bond->lock); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - /* must be called only after the slave has been - * detached from the list and the current_slave - * has been replaced (if our_slave == old_current) - */ - bond_alb_deinit_slave(bond, our_slave); - } + bond_del_vlans_from_slave(bond, slave_dev); - break; + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - write_unlock_bh(&bond->lock); - - if (our_slave == (slave_t *)bond) { - /* if we get here, it's because the device was not found */ - printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); - return -EINVAL; - } - - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - /* If the mode USES_PRIMARY, then we should only remove its - * promisc settings if it was the current_slave, but that was - * already taken care of above when we detached the slave - */ - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave, -1); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); } - } - - /* undo settings and restore original values */ - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave, master); - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave, -1); + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } - netdev_set_master(slave, NULL); + netdev_set_master(slave_dev, NULL); /* close slave before restoring its mac address */ - dev_close(slave); + dev_close(slave_dev); if (app_abi_ver >= 1) { /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); - addr.sa_family = slave->type; - slave->set_mac_address(slave, &addr); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + addr.sa_family = slave_dev->type; + slave_dev->set_mac_address(slave_dev, &addr); } /* restore the original state of the * IFF_NOARP flag that might have been * set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { - slave->flags &= ~IFF_NOARP; + if ((slave->original_flags & IFF_NOARP) == 0) { + slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); - - /* if the last slave was removed, zero the mac address - * of the master so it will be set by the application - * to the mac address of the first slave - */ - if (bond->next == (slave_t*)bond) { - memset(master->dev_addr, 0, master->addr_len); - } + kfree(slave); return 0; /* deletion OK */ } -/* +/* * This function releases all slaves. */ -static int bond_release_all(struct net_device *master) +static int bond_release_all(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *our_slave, *old_current; + struct bonding *bond = bond_dev->priv; + struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; - int err = 0; - - if (master == NULL) { - return -ENODEV; - } - - if (master->flags & IFF_SLAVE) { - return -EINVAL; - } - - bond = (struct bonding *) master->priv; write_lock_bh(&bond->lock); - if (bond->next == (struct slave *) bond) { - err = -EINVAL; + + if (bond->slave_cnt == 0) { goto out; } - old_current = bond->current_slave; - change_active_interface(bond, NULL); bond->current_arp_slave = NULL; bond->primary_slave = NULL; + bond_change_active_slave(bond, NULL); - while ((our_slave = bond->prev) != (slave_t *)bond) { + while ((slave = bond->first_slave) != NULL) { /* Inform AD package of unbinding of slave * before slave is detached from the list. */ - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_unbind_slave(our_slave); + if (bond->params.mode == BOND_MODE_8023AD) { + bond_3ad_unbind_slave(slave); } - slave_dev = our_slave->dev; - bond_detach_slave(bond, our_slave); + slave_dev = slave->dev; + bond_detach_slave(bond, slave); - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { /* must be called only after the slave * has been detached from the list */ - bond_alb_deinit_slave(bond, our_slave); + bond_alb_deinit_slave(bond, slave); } /* now that the slave is detached, unlock and perform @@ -2180,20 +2225,25 @@ */ write_unlock_bh(&bond->lock); - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) { - if (!USES_PRIMARY(bond_mode)) { - dev_set_promiscuity(slave_dev, -1); + bond_del_vlans_from_slave(bond, slave_dev); + + /* If the mode USES_PRIMARY, then we should only remove its + * promisc and mc settings if it was the curr_active_slave, but that was + * already taken care of above when we detached the slave + */ + if (!USES_PRIMARY(bond->params.mode)) { + /* unset promiscuity level from slave */ + if (bond_dev->flags & IFF_PROMISC) { + dev_set_promiscuity(slave_dev, -1); } - } - if (multicast_mode == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave_dev, master); - - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave_dev, -1); + /* unset allmulti level from slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + dev_set_allmulti(slave_dev, -1); + } + + /* flush master's mc_list from slave */ + bond_mc_list_flush(bond_dev, slave_dev); } netdev_set_master(slave_dev, NULL); @@ -2203,7 +2253,7 @@ if (app_abi_ver >= 1) { /* restore original ("permanent") mac address*/ - memcpy(addr.sa_data, our_slave->perm_hwaddr, ETH_ALEN); + memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); addr.sa_family = slave_dev->type; slave_dev->set_mac_address(slave_dev, &addr); } @@ -2211,11 +2261,11 @@ /* restore the original state of the IFF_NOARP flag that might have * been set by bond_set_slave_inactive_flags() */ - if ((our_slave->original_flags & IFF_NOARP) == 0) { + if ((slave->original_flags & IFF_NOARP) == 0) { slave_dev->flags &= ~IFF_NOARP; } - kfree(our_slave); + kfree(slave); /* re-acquire the lock before getting the next slave */ write_lock_bh(&bond->lock); @@ -2225,124 +2275,304 @@ * set by the application to the mac address of the * first slave */ - memset(master->dev_addr, 0, master->addr_len); + memset(bond_dev->dev_addr, 0, bond_dev->addr_len); + + if (list_empty(&bond->vlan_list)) { + bond_dev->features |= NETIF_F_VLAN_CHALLENGED; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: clearing HW address of %s while it " + "still has VLANs.\n", + bond_dev->name); + printk(KERN_WARNING DRV_NAME + ": When re-adding slaves, make sure the bond's " + "HW address matches its VLANs'.\n"); + } - printk (KERN_INFO "%s: released all slaves\n", master->name); + printk(KERN_INFO DRV_NAME + ": %s: released all slaves\n", + bond_dev->name); out: write_unlock_bh(&bond->lock); - return err; + return 0; } -/* this function is called regularly to monitor each slave's link. */ -static void bond_mii_monitor(struct net_device *master) +/* + * This function changes the active slave to slave . + * It returns -EINVAL in the following cases. + * - is not found in the list. + * - There is not active slave now. + * - is already active. + * - The link state of is not BOND_LINK_UP. + * - is not running. + * In these cases, this fuction does nothing. + * In the other cases, currnt_slave pointer is changed and 0 is returned. + */ +static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave, *oldcurrent; - int slave_died = 0; - int do_failover = 0; + struct bonding *bond = bond_dev->priv; + struct slave *old_active = NULL; + struct slave *new_active = NULL; + int res = 0; - read_lock(&bond->lock); + if (!USES_PRIMARY(bond->params.mode)) { + return -EINVAL; + } - /* we will try to read the link status of each of our slaves, and - * set their IFF_RUNNING flag appropriately. For each slave not - * supporting MII status, we won't do anything so that a user-space - * program could monitor the link itself if needed. - */ + /* Verify that master_dev is indeed the master of slave_dev */ + if (!(slave_dev->flags & IFF_SLAVE) || + (slave_dev->master != bond_dev)) { + return -EINVAL; + } - slave = (slave_t *)bond; + write_lock_bh(&bond->lock); - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + old_active = bond->curr_active_slave; + new_active = bond_get_slave_by_dev(bond, slave_dev); - while ((slave = slave->prev) != (slave_t *)bond) { - struct net_device *dev = slave->dev; - int link_state; - u16 old_speed = slave->speed; - u8 old_duplex = slave->duplex; - - link_state = bond_check_dev_link(dev, 0); + /* + * Changing to the current active: do nothing; return success. + */ + if (new_active && (new_active == old_active)) { + write_unlock_bh(&bond->lock); + return 0; + } - switch (slave->link) { - case BOND_LINK_UP: /* the link was up */ - if (link_state == BMSR_LSTATUS) { - /* link stays up, nothing more to do */ - break; - } - else { /* link going down */ - slave->link = BOND_LINK_FAIL; - slave->delay = downdelay; - if (slave->link_failure_count < UINT_MAX) { - slave->link_failure_count++; - } - if (downdelay > 0) { - printk (KERN_INFO - "%s: link status down for %sinterface " - "%s, disabling it in %d ms.\n", - master->name, - IS_UP(dev) - ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) - ? ((slave == oldcurrent) - ? "active " : "backup ") - : "") - : "idle ", - dev->name, - downdelay * miimon); - } - } - /* no break ! fall through the BOND_LINK_FAIL test to - ensure proper action to be taken - */ - case BOND_LINK_FAIL: /* the link has just gone down */ - if (link_state != BMSR_LSTATUS) { - /* link stays down */ - if (slave->delay <= 0) { - /* link down for too long time */ - slave->link = BOND_LINK_DOWN; - /* in active/backup mode, we must - * completely disable this interface - */ - if ((bond_mode == BOND_MODE_ACTIVEBACKUP) || - (bond_mode == BOND_MODE_8023AD)) { - bond_set_slave_inactive_flags(slave); - } + if ((new_active) && + (old_active) && + (new_active->link == BOND_LINK_UP) && + IS_UP(new_active->dev)) { + bond_change_active_slave(bond, new_active); + } else { + res = -EINVAL; + } - printk(KERN_INFO - "%s: link status definitely down " - "for interface %s, disabling it", - master->name, - dev->name); + write_unlock_bh(&bond->lock); - /* notify ad that the link status has changed */ - if (bond_mode == BOND_MODE_8023AD) { - bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); - } + return res; +} - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { - bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); - } +static int bond_ethtool_ioctl(struct net_device *bond_dev, struct ifreq *ifr) +{ + struct ethtool_drvinfo info; + void *addr = ifr->ifr_data; + uint32_t cmd; - if (slave == oldcurrent) { - do_failover = 1; - } + if (get_user(cmd, (uint32_t *)addr)) { + return -EFAULT; + } - slave_died = 1; - } else { - slave->delay--; - } + switch (cmd) { + case ETHTOOL_GDRVINFO: + if (copy_from_user(&info, addr, sizeof(info))) { + return -EFAULT; + } + + if (strcmp(info.driver, "ifenslave") == 0) { + int new_abi_ver; + char *endptr; + + new_abi_ver = simple_strtoul(info.fw_version, + &endptr, 0); + if (*endptr) { + printk(KERN_ERR DRV_NAME + ": Error: got invalid ABI " + "version from application\n"); + + return -EINVAL; + } + + if (orig_app_abi_ver == -1) { + orig_app_abi_ver = new_abi_ver; + } + + app_abi_ver = new_abi_ver; + } + + strncpy(info.driver, DRV_NAME, 32); + strncpy(info.version, DRV_VERSION, 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + + if (copy_to_user(addr, &info, sizeof(info))) { + return -EFAULT; + } + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) +{ + struct bonding *bond = bond_dev->priv; + + info->bond_mode = bond->params.mode; + info->miimon = bond->params.miimon; + + read_lock_bh(&bond->lock); + info->num_slaves = bond->slave_cnt; + read_unlock_bh(&bond->lock); + + return 0; +} + +static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int i, found = 0; + + if (info->slave_id < 0) { + return -ENODEV; + } + + read_lock_bh(&bond->lock); + + bond_for_each_slave(bond, slave, i) { + if (i == (int)info->slave_id) { + found = 1; + break; + } + } + + read_unlock_bh(&bond->lock); + + if (found) { + strcpy(info->slave_name, slave->dev->name); + info->link = slave->link; + info->state = slave->state; + info->link_failure_count = slave->link_failure_count; + } else { + return -ENODEV; + } + + return 0; +} + +/*-------------------------------- Monitoring -------------------------------*/ + +/* this function is called regularly to monitor each slave's link. */ +static void bond_mii_monitor(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; + int do_failover = 0; + int delta_in_ticks; + int i; + + read_lock(&bond->lock); + + delta_in_ticks = (bond->params.miimon * HZ) / 1000; + + if (bond->kill_timers) { + goto out; + } + + if (bond->slave_cnt == 0) { + goto re_arm; + } + + /* we will try to read the link status of each of our slaves, and + * set their IFF_RUNNING flag appropriately. For each slave not + * supporting MII status, we won't do anything so that a user-space + * program could monitor the link itself if needed. + */ + + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + bond_for_each_slave(bond, slave, i) { + struct net_device *slave_dev = slave->dev; + int link_state; + u16 old_speed = slave->speed; + u8 old_duplex = slave->duplex; + + link_state = bond_check_dev_link(bond, slave_dev, 0); + + switch (slave->link) { + case BOND_LINK_UP: /* the link was up */ + if (link_state == BMSR_LSTATUS) { + /* link stays up, nothing more to do */ + break; + } else { /* link going down */ + slave->link = BOND_LINK_FAIL; + slave->delay = bond->params.downdelay; + + if (slave->link_failure_count < UINT_MAX) { + slave->link_failure_count++; + } + + if (bond->params.downdelay) { + printk(KERN_INFO DRV_NAME + ": %s: link status down for %s " + "interface %s, disabling it in " + "%d ms.\n", + bond_dev->name, + IS_UP(slave_dev) + ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) + ? ((slave == oldcurrent) + ? "active " : "backup ") + : "") + : "idle ", + slave_dev->name, + bond->params.downdelay * bond->params.miimon); + } + } + /* no break ! fall through the BOND_LINK_FAIL test to + ensure proper action to be taken + */ + case BOND_LINK_FAIL: /* the link has just gone down */ + if (link_state != BMSR_LSTATUS) { + /* link stays down */ + if (slave->delay <= 0) { + /* link down for too long time */ + slave->link = BOND_LINK_DOWN; + + /* in active/backup mode, we must + * completely disable this interface + */ + if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) || + (bond->params.mode == BOND_MODE_8023AD)) { + bond_set_slave_inactive_flags(slave); + } + + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "down for interface %s, " + "disabling it\n", + bond_dev->name, + slave_dev->name); + + /* notify ad that the link status has changed */ + if (bond->params.mode == BOND_MODE_8023AD) { + bond_3ad_handle_link_change(slave, BOND_LINK_DOWN); + } + + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + bond_alb_handle_link_change(bond, slave, BOND_LINK_DOWN); + } + + if (slave == oldcurrent) { + do_failover = 1; + } + } else { + slave->delay--; + } } else { /* link up again */ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - printk(KERN_INFO - "%s: link status up again after %d ms " - "for interface %s.\n", - master->name, - (downdelay - slave->delay) * miimon, - dev->name); + printk(KERN_INFO DRV_NAME + ": %s: link status up again after %d " + "ms for interface %s.\n", + bond_dev->name, + (bond->params.downdelay - slave->delay) * bond->params.miimon, + slave_dev->name); } break; case BOND_LINK_DOWN: /* the link was down */ @@ -2351,17 +2581,18 @@ break; } else { /* link going up */ slave->link = BOND_LINK_BACK; - slave->delay = updelay; - - if (updelay > 0) { + slave->delay = bond->params.updelay; + + if (bond->params.updelay) { /* if updelay == 0, no need to advertise about a 0 ms delay */ - printk (KERN_INFO - "%s: link status up for interface" - " %s, enabling it in %d ms.\n", - master->name, - dev->name, - updelay * miimon); + printk(KERN_INFO DRV_NAME + ": %s: link status up for " + "interface %s, enabling it " + "in %d ms.\n", + bond_dev->name, + slave_dev->name, + bond->params.updelay * bond->params.miimon); } } /* no break ! fall through the BOND_LINK_BACK state in @@ -2371,12 +2602,13 @@ if (link_state != BMSR_LSTATUS) { /* link down again */ slave->link = BOND_LINK_DOWN; - printk(KERN_INFO - "%s: link status down again after %d ms " - "for interface %s.\n", - master->name, - (updelay - slave->delay) * miimon, - dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: link status down again after %d " + "ms for interface %s.\n", + bond_dev->name, + (bond->params.updelay - slave->delay) * bond->params.miimon, + slave_dev->name); } else { /* link stays up */ if (slave->delay == 0) { @@ -2384,11 +2616,10 @@ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { /* prevent it from being the active one */ slave->state = BOND_STATE_BACKUP; - } - else if (bond_mode != BOND_MODE_ACTIVEBACKUP) { + } else if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; } else if (slave != bond->primary_slave) { @@ -2396,23 +2627,23 @@ slave->state = BOND_STATE_BACKUP; } - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s.\n", - master->name, - dev->name); - + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s.\n", + bond_dev->name, + slave_dev->name); + /* notify ad that the link status has changed */ - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { bond_3ad_handle_link_change(slave, BOND_LINK_UP); } - if ((bond_mode == BOND_MODE_TLB) || - (bond_mode == BOND_MODE_ALB)) { + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); } - if ((oldcurrent == NULL) || + if ((!oldcurrent) || (slave == bond->primary_slave)) { do_failover = 1; } @@ -2421,120 +2652,128 @@ } } break; - } /* end of switch */ + default: + /* Should not happen */ + printk(KERN_ERR "bonding: Error: %s Illegal value (link=%d)\n", + slave->dev->name, slave->link); + goto out; + } /* end of switch (slave->link) */ bond_update_speed_duplex(slave); - if (bond_mode == BOND_MODE_8023AD) { + if (bond->params.mode == BOND_MODE_8023AD) { if (old_speed != slave->speed) { bond_3ad_adapter_speed_changed(slave); } + if (old_duplex != slave->duplex) { bond_3ad_adapter_duplex_changed(slave); } } - } /* end of while */ + } /* end of for */ if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + bond_select_active_slave(bond); + + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + if (bond->params.miimon) { + mod_timer(&bond->mii_timer, jiffies + delta_in_ticks); + } +out: read_unlock(&bond->lock); - /* re-arm the timer */ - mod_timer(&bond->mii_timer, jiffies + (miimon * HZ / 1000)); } -/* - * this function is called regularly to monitor each slave's link +static void bond_arp_send_all(struct bonding *bond, struct slave *slave) +{ + int i; + u32 *targets = bond->params.arp_targets; + + for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { + arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev, + my_ip, NULL, slave->dev->dev_addr, + NULL); + } +} + +/* + * this function is called regularly to monitor each slave's link * ensuring that traffic is being sent and received when arp monitoring - * is used in load-balancing mode. if the adapter has been dormant, then an - * arp is transmitted to generate traffic. see activebackup_arp_monitor for - * arp monitoring in active backup mode. - */ -static void loadbalance_arp_monitor(struct net_device *master) -{ - bonding_t *bond; - slave_t *slave, *oldcurrent; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); + * is used in load-balancing mode. if the adapter has been dormant, then an + * arp is transmitted to generate traffic. see activebackup_arp_monitor for + * arp monitoring in active backup mode. + */ +static void bond_loadbalance_arp_mon(struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave, *oldcurrent; int do_failover = 0; + int delta_in_ticks; + int i; - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + read_lock(&bond->lock); - /* TODO: investigate why rtnl_shlock_nowait and rtnl_exlock_nowait - * are called below and add comment why they are required... - */ - if ((!IS_UP(master)) || rtnl_shlock_nowait()) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; - if (rtnl_exlock_nowait()) { - rtnl_shunlock(); - mod_timer(&bond->arp_timer, next_timer); - return; + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - read_lock(&bond->ptrlock); - oldcurrent = bond->current_slave; - read_unlock(&bond->ptrlock); + read_lock(&bond->curr_slave_lock); + oldcurrent = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); /* see if any of the previous devices are up now (i.e. they have - * xmt and rcv traffic). the current_slave does not come into + * xmt and rcv traffic). the curr_active_slave does not come into * the picture unless it is null. also, slave->jiffies is not needed * here because we send an arp on each slave and give a slave as * long as it needs to get the tx/rx within the delta. * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - - if (((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks) && - ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks)) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) && + ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) { slave->link = BOND_LINK_UP; slave->state = BOND_STATE_ACTIVE; /* primary_slave has no meaning in round-robin - * mode. the window of a slave being up and - * current_slave being null after enslaving + * mode. the window of a slave being up and + * curr_active_slave being null after enslaving * is closed. */ - if (oldcurrent == NULL) { - printk(KERN_INFO - "%s: link status definitely up " - "for interface %s, ", - master->name, - slave->dev->name); + if (!oldcurrent) { + printk(KERN_INFO DRV_NAME + ": %s: link status definitely " + "up for interface %s, ", + bond_dev->name, + slave->dev->name); do_failover = 1; } else { - printk(KERN_INFO - "%s: interface %s is now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now up\n", + bond_dev->name, + slave->dev->name); } - } + } } else { /* slave->link == BOND_LINK_UP */ @@ -2542,224 +2781,237 @@ * when the source ip is 0, so don't take the link down * if we don't know our ip yet */ - if (((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && my_ip !=0)) { + if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) { + slave->link = BOND_LINK_DOWN; slave->state = BOND_STATE_BACKUP; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO - "%s: interface %s is now down.\n", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: interface %s is now down.\n", + bond_dev->name, slave->dev->name); if (slave == oldcurrent) { do_failover = 1; } } - } + } - /* note: if switch is in round-robin mode, all links + /* note: if switch is in round-robin mode, all links * must tx arp to ensure all links rx an arp - otherwise - * links may oscillate or not come up at all; if switch is - * in something like xor mode, there is nothing we can - * do - all replies will be rx'ed on same link causing slaves + * links may oscillate or not come up at all; if switch is + * in something like xor mode, there is nothing we can + * do - all replies will be rx'ed on same link causing slaves * to be unstable during low/no traffic periods */ if (IS_UP(slave->dev)) { - arp_send_all(slave); + bond_arp_send_all(bond, slave); } } if (do_failover) { - write_lock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); - reselect_active_interface(bond); - if (oldcurrent && !bond->current_slave) { - printk(KERN_INFO - "%s: now running without any active interface !\n", - master->name); + if (oldcurrent && !bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: now running without any active " + "interface !\n", + bond_dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } +re_arm: + if (bond->params.arp_interval) { + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); + } +out: read_unlock(&bond->lock); - rtnl_exunlock(); - rtnl_shunlock(); - - /* re-arm the timer */ - mod_timer(&bond->arp_timer, next_timer); } -/* +/* * When using arp monitoring in active-backup mode, this function is * called to determine if any backup slaves have went down or a new * current slave needs to be found. - * The backup slaves never generate traffic, they are considered up by merely - * receiving traffic. If the current slave goes down, each backup slave will - * be given the opportunity to tx/rx an arp before being taken down - this - * prevents all slaves from being taken down due to the current slave not + * The backup slaves never generate traffic, they are considered up by merely + * receiving traffic. If the current slave goes down, each backup slave will + * be given the opportunity to tx/rx an arp before being taken down - this + * prevents all slaves from being taken down due to the current slave not * sending any traffic for the backups to receive. The arps are not necessarily - * necessary, any tx and rx traffic will keep the current slave up. While any - * rx traffic will keep the backup slaves up, the current slave is responsible - * for generating traffic to keep them up regardless of any other traffic they + * necessary, any tx and rx traffic will keep the current slave up. While any + * rx traffic will keep the backup slaves up, the current slave is responsible + * for generating traffic to keep them up regardless of any other traffic they * may have received. * see loadbalance_arp_monitor for arp monitoring in load balancing mode */ -static void activebackup_arp_monitor(struct net_device *master) +static void bond_activebackup_arp_mon(struct net_device *bond_dev) { - bonding_t *bond; - slave_t *slave; - int the_delta_in_ticks = arp_interval * HZ / 1000; - int next_timer = jiffies + (arp_interval * HZ / 1000); - - bond = (struct bonding *) master->priv; - if (master->priv == NULL) { - mod_timer(&bond->arp_timer, next_timer); - return; - } + struct bonding *bond = bond_dev->priv; + struct slave *slave; + int delta_in_ticks; + int i; - if (!IS_UP(master)) { - mod_timer(&bond->arp_timer, next_timer); - return; + read_lock(&bond->lock); + + delta_in_ticks = (bond->params.arp_interval * HZ) / 1000; + + if (bond->kill_timers) { + goto out; } - read_lock(&bond->lock); + if (bond->slave_cnt == 0) { + goto re_arm; + } - /* determine if any slave has come up or any backup slave has - * gone down + /* determine if any slave has come up or any backup slave has + * gone down * TODO: what about up/down delay in arp mode? it wasn't here before - * so it can wait + * so it can wait */ - slave = (slave_t *)bond; - while ((slave = slave->prev) != (slave_t *)bond) { - - if (slave->link != BOND_LINK_UP) { - if ((jiffies - slave->dev->last_rx) <= - the_delta_in_ticks) { + bond_for_each_slave(bond, slave, i) { + if (slave->link != BOND_LINK_UP) { + if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) { slave->link = BOND_LINK_UP; - write_lock(&bond->ptrlock); - if ((bond->current_slave == NULL) && - ((jiffies - slave->dev->trans_start) <= - the_delta_in_ticks)) { - change_active_interface(bond, slave); + + write_lock(&bond->curr_slave_lock); + + if ((!bond->curr_active_slave) && + ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) { + bond_change_active_slave(bond, slave); bond->current_arp_slave = NULL; - } else if (bond->current_slave != slave) { - /* this slave has just come up but we + } else if (bond->curr_active_slave != slave) { + /* this slave has just come up but we * already have a current slave; this * can also happen if bond_enslave adds - * a new slave that is up while we are + * a new slave that is up while we are * searching for a new slave */ bond_set_slave_inactive_flags(slave); bond->current_arp_slave = NULL; } - if (slave == bond->current_slave) { - printk(KERN_INFO - "%s: %s is up and now the " - "active interface\n", - master->name, - slave->dev->name); + if (slave == bond->curr_active_slave) { + printk(KERN_INFO DRV_NAME + ": %s: %s is up and now the " + "active interface\n", + bond_dev->name, + slave->dev->name); } else { - printk(KERN_INFO - "%s: backup interface %s is " - "now up\n", - master->name, - slave->dev->name); + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now up\n", + bond_dev->name, + slave->dev->name); } - write_unlock(&bond->ptrlock); + write_unlock(&bond->curr_slave_lock); } } else { - read_lock(&bond->ptrlock); - if ((slave != bond->current_slave) && - (bond->current_arp_slave == NULL) && - (((jiffies - slave->dev->last_rx) >= - 3*the_delta_in_ticks) && (my_ip != 0))) { - /* a backup slave has gone down; three times - * the delta allows the current slave to be + read_lock(&bond->curr_slave_lock); + + if ((slave != bond->curr_active_slave) && + (!bond->current_arp_slave) && + (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) && + my_ip)) { + /* a backup slave has gone down; three times + * the delta allows the current slave to be * taken out before the backup slave. * note: a non-null current_arp_slave indicates - * the current_slave went down and we are - * searching for a new one; under this - * condition we only take the current_slave - * down - this gives each slave a chance to + * the curr_active_slave went down and we are + * searching for a new one; under this + * condition we only take the curr_active_slave + * down - this gives each slave a chance to * tx/rx traffic before being taken out */ - read_unlock(&bond->ptrlock); + + read_unlock(&bond->curr_slave_lock); + slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } + bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface %s is now down\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is now down\n", + bond_dev->name, + slave->dev->name); } else { - read_unlock(&bond->ptrlock); + read_unlock(&bond->curr_slave_lock); } } } - read_lock(&bond->ptrlock); - slave = bond->current_slave; - read_unlock(&bond->ptrlock); - - if (slave != NULL) { + read_lock(&bond->curr_slave_lock); + slave = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + if (slave) { /* if we have sent traffic in the past 2*arp_intervals but - * haven't xmit and rx traffic in that time interval, select + * haven't xmit and rx traffic in that time interval, select * a different slave. slave->jiffies is only updated when - * a slave first becomes the current_slave - not necessarily - * after every arp; this ensures the slave has a full 2*delta - * before being taken out. if a primary is being used, check - * if it is up and needs to take over as the current_slave + * a slave first becomes the curr_active_slave - not necessarily + * after every arp; this ensures the slave has a full 2*delta + * before being taken out. if a primary is being used, check + * if it is up and needs to take over as the curr_active_slave */ - if ((((jiffies - slave->dev->trans_start) >= - (2*the_delta_in_ticks)) || - (((jiffies - slave->dev->last_rx) >= - (2*the_delta_in_ticks)) && (my_ip != 0))) && - ((jiffies - slave->jiffies) >= 2*the_delta_in_ticks)) { + if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) || + (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) && + my_ip)) && + ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) { slave->link = BOND_LINK_DOWN; + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } - printk(KERN_INFO "%s: link status down for " - "active interface %s, disabling it", - master->name, + + printk(KERN_INFO DRV_NAME + ": %s: link status down for active interface " + "%s, disabling it\n", + bond_dev->name, slave->dev->name); - write_lock(&bond->ptrlock); - reselect_active_interface(bond); - slave = bond->current_slave; - write_unlock(&bond->ptrlock); + + write_lock(&bond->curr_slave_lock); + + bond_select_active_slave(bond); + slave = bond->curr_active_slave; + + write_unlock(&bond->curr_slave_lock); + bond->current_arp_slave = slave; - if (slave != NULL) { + + if (slave) { slave->jiffies = jiffies; } - - } else if ((bond->primary_slave != NULL) && - (bond->primary_slave != slave) && + } else if ((bond->primary_slave) && + (bond->primary_slave != slave) && (bond->primary_slave->link == BOND_LINK_UP)) { - /* at this point, slave is the current_slave */ - printk(KERN_INFO - "%s: changing from interface %s to primary " + /* at this point, slave is the curr_active_slave */ + printk(KERN_INFO DRV_NAME + ": %s: changing from interface %s to primary " "interface %s\n", - master->name, - slave->dev->name, + bond_dev->name, + slave->dev->name, bond->primary_slave->dev->name); - + /* primary is up so switch to it */ - write_lock(&bond->ptrlock); - change_active_interface(bond, bond->primary_slave); - write_unlock(&bond->ptrlock); + write_lock(&bond->curr_slave_lock); + bond_change_active_slave(bond, bond->primary_slave); + write_unlock(&bond->curr_slave_lock); + slave = bond->primary_slave; slave->jiffies = jiffies; } else { @@ -2769,567 +3021,618 @@ /* the current slave must tx an arp to ensure backup slaves * rx traffic */ - if ((slave != NULL) && (my_ip != 0)) { - arp_send_all(slave); + if (slave && my_ip) { + bond_arp_send_all(bond, slave); } } - /* if we don't have a current_slave, search for the next available - * backup slave from the current_arp_slave and make it the candidate - * for becoming the current_slave + /* if we don't have a curr_active_slave, search for the next available + * backup slave from the current_arp_slave and make it the candidate + * for becoming the curr_active_slave */ - if (slave == NULL) { - - if ((bond->current_arp_slave == NULL) || - (bond->current_arp_slave == (slave_t *)bond)) { - bond->current_arp_slave = bond->prev; - } + if (!slave) { + if (!bond->current_arp_slave) { + bond->current_arp_slave = bond->first_slave; + } - if (bond->current_arp_slave != (slave_t *)bond) { + if (bond->current_arp_slave) { bond_set_slave_inactive_flags(bond->current_arp_slave); - slave = bond->current_arp_slave->next; /* search for next candidate */ - do { + bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave) { if (IS_UP(slave->dev)) { slave->link = BOND_LINK_BACK; bond_set_slave_active_flags(slave); - arp_send_all(slave); + bond_arp_send_all(bond, slave); slave->jiffies = jiffies; bond->current_arp_slave = slave; break; } - /* if the link state is up at this point, we - * mark it down - this can happen if we have - * simultaneous link failures and - * reselect_active_interface doesn't make this - * one the current slave so it is still marked + /* if the link state is up at this point, we + * mark it down - this can happen if we have + * simultaneous link failures and + * reselect_active_interface doesn't make this + * one the current slave so it is still marked * up when it is actually down */ if (slave->link == BOND_LINK_UP) { slave->link = BOND_LINK_DOWN; - if (slave->link_failure_count < - UINT_MAX) { + if (slave->link_failure_count < UINT_MAX) { slave->link_failure_count++; } bond_set_slave_inactive_flags(slave); - printk(KERN_INFO - "%s: backup interface " - "%s is now down.\n", - master->name, - slave->dev->name); + + printk(KERN_INFO DRV_NAME + ": %s: backup interface %s is " + "now down.\n", + bond_dev->name, + slave->dev->name); } - } while ((slave = slave->next) != - bond->current_arp_slave->next); + } } } +re_arm: + if (bond->params.arp_interval) { + mod_timer(&bond->arp_timer, jiffies + delta_in_ticks); + } +out: read_unlock(&bond->lock); - mod_timer(&bond->arp_timer, next_timer); -} - -static int bond_sethwaddr(struct net_device *master, struct net_device *slave) -{ -#ifdef BONDING_DEBUG - printk(KERN_CRIT "bond_sethwaddr: master=%x\n", (unsigned int)master); - printk(KERN_CRIT "bond_sethwaddr: slave=%x\n", (unsigned int)slave); - printk(KERN_CRIT "bond_sethwaddr: slave->addr_len=%d\n", slave->addr_len); -#endif - memcpy(master->dev_addr, slave->dev_addr, slave->addr_len); - return 0; } -static int bond_info_query(struct net_device *master, struct ifbond *info) -{ - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - - info->bond_mode = bond_mode; - info->num_slaves = 0; - info->miimon = miimon; +/*------------------------------ proc/seq_file-------------------------------*/ - read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { - info->num_slaves++; - } - read_unlock_bh(&bond->lock); +#ifdef CONFIG_PROC_FS - return 0; -} +#define SEQ_START_TOKEN ((void *)1) -static int bond_slave_info_query(struct net_device *master, - struct ifslave *info) +static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) { - bonding_t *bond = (struct bonding *) master->priv; - slave_t *slave; - int cur_ndx = 0; - - if (info->slave_id < 0) { - return -ENODEV; - } + struct bonding *bond = seq->private; + loff_t off = 0; + struct slave *slave; + int i; + /* make sure the bond won't be taken away */ + read_lock(&dev_base_lock); read_lock_bh(&bond->lock); - for (slave = bond->prev; - slave != (slave_t *)bond && cur_ndx < info->slave_id; - slave = slave->prev) { - cur_ndx++; + + if (*pos == 0) { + return SEQ_START_TOKEN; } - read_unlock_bh(&bond->lock); - if (slave != (slave_t *)bond) { - strcpy(info->slave_name, slave->dev->name); - info->link = slave->link; - info->state = slave->state; - info->link_failure_count = slave->link_failure_count; - } else { - return -ENODEV; + bond_for_each_slave(bond, slave, i) { + if (++off == *pos) { + return slave; + } } - return 0; + return NULL; } -static int bond_ethtool_ioctl(struct net_device *master_dev, struct ifreq *ifr) +static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - void *addr = ifr->ifr_data; - uint32_t cmd; - - if (get_user(cmd, (uint32_t *) addr)) - return -EFAULT; + struct bonding *bond = seq->private; + struct slave *slave = v; - switch (cmd) { + ++*pos; + if (v == SEQ_START_TOKEN) { + return bond->first_slave; + } - case ETHTOOL_GDRVINFO: - { - struct ethtool_drvinfo info; - char *endptr; + slave = slave->next; - if (copy_from_user(&info, addr, sizeof(info))) - return -EFAULT; + return (slave == bond->first_slave) ? NULL : slave; +} - if (strcmp(info.driver, "ifenslave") == 0) { - int new_abi_ver; +static void bond_info_seq_stop(struct seq_file *seq, void *v) +{ + struct bonding *bond = seq->private; - new_abi_ver = simple_strtoul(info.fw_version, - &endptr, 0); - if (*endptr) { - printk(KERN_ERR - "bonding: Error: got invalid ABI" - " version from application\n"); + read_unlock_bh(&bond->lock); + read_unlock(&dev_base_lock); +} - return -EINVAL; - } +static void bond_info_show_master(struct seq_file *seq) +{ + struct bonding *bond = seq->private; + struct slave *curr; - if (orig_app_abi_ver == -1) { - orig_app_abi_ver = new_abi_ver; - } + read_lock(&bond->curr_slave_lock); + curr = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + seq_printf(seq, "Bonding Mode: %s\n", + bond_mode_name(bond->params.mode)); + + if (USES_PRIMARY(bond->params.mode)) { + seq_printf(seq, "Primary Slave: %s\n", + (bond->params.primary[0]) ? + bond->params.primary : "None"); - app_abi_ver = new_abi_ver; - } + seq_printf(seq, "Currently Active Slave: %s\n", + (curr) ? curr->dev->name : "None"); + } - strncpy(info.driver, DRV_NAME, 32); - strncpy(info.version, DRV_VERSION, 32); - snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); + seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon); + seq_printf(seq, "Up Delay (ms): %d\n", + bond->params.updelay * bond->params.miimon); + seq_printf(seq, "Down Delay (ms): %d\n", + bond->params.downdelay * bond->params.miimon); - if (copy_to_user(addr, &info, sizeof(info))) - return -EFAULT; + if (bond->params.mode == BOND_MODE_8023AD) { + struct ad_info ad_info; - return 0; + seq_puts(seq, "\n802.3ad info\n"); + seq_printf(seq, "LACP rate: %s\n", + (bond->params.lacp_fast) ? "fast" : "slow"); + + if (bond_3ad_get_active_agg_info(bond, &ad_info)) { + seq_printf(seq, "bond %s has no active aggregator\n", + bond->dev->name); + } else { + seq_printf(seq, "Active Aggregator Info:\n"); + + seq_printf(seq, "\tAggregator ID: %d\n", + ad_info.aggregator_id); + seq_printf(seq, "\tNumber of ports: %d\n", + ad_info.ports); + seq_printf(seq, "\tActor Key: %d\n", + ad_info.actor_key); + seq_printf(seq, "\tPartner Key: %d\n", + ad_info.partner_key); + seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", + ad_info.partner_system[0], + ad_info.partner_system[1], + ad_info.partner_system[2], + ad_info.partner_system[3], + ad_info.partner_system[4], + ad_info.partner_system[5]); } - break; - default: - return -EOPNOTSUPP; } } -static int bond_ioctl(struct net_device *master_dev, struct ifreq *ifr, int cmd) +static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { - struct net_device *slave_dev = NULL; - struct ifbond *u_binfo = NULL, k_binfo; - struct ifslave *u_sinfo = NULL, k_sinfo; - struct mii_ioctl_data *mii = NULL; - int prev_abi_ver = orig_app_abi_ver; - int ret = 0; + struct bonding *bond = seq->private; -#ifdef BONDING_DEBUG - printk(KERN_INFO "bond_ioctl: master=%s, cmd=%d\n", - master_dev->name, cmd); -#endif + seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); + seq_printf(seq, "MII Status: %s\n", + (slave->link == BOND_LINK_UP) ? "up" : "down"); + seq_printf(seq, "Link Failure Count: %d\n", + slave->link_failure_count); - switch (cmd) { - case SIOCETHTOOL: - return bond_ethtool_ioctl(master_dev, ifr); + if (app_abi_ver >= 1) { + seq_printf(seq, + "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", + slave->perm_hwaddr[0], + slave->perm_hwaddr[1], + slave->perm_hwaddr[2], + slave->perm_hwaddr[3], + slave->perm_hwaddr[4], + slave->perm_hwaddr[5]); + } - case SIOCGMIIPHY: - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - mii->phy_id = 0; - /* Fall Through */ - case SIOCGMIIREG: - /* - * We do this again just in case we were called by SIOCGMIIREG - * instead of SIOCGMIIPHY. - */ - mii = (struct mii_ioctl_data *)&ifr->ifr_data; - if (mii == NULL) { - return -EINVAL; - } - if (mii->reg_num == 1) { - mii->val_out = bond_check_mii_link( - (struct bonding *)master_dev->priv); - } - return 0; - case BOND_INFO_QUERY_OLD: - case SIOCBONDINFOQUERY: - u_binfo = (struct ifbond *)ifr->ifr_data; - if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { - return -EFAULT; - } - ret = bond_info_query(master_dev, &k_binfo); - if (ret == 0) { - if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { - return -EFAULT; - } - } - return ret; - case BOND_SLAVE_INFO_QUERY_OLD: - case SIOCBONDSLAVEINFOQUERY: - u_sinfo = (struct ifslave *)ifr->ifr_data; - if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { - return -EFAULT; - } - ret = bond_slave_info_query(master_dev, &k_sinfo); - if (ret == 0) { - if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { - return -EFAULT; - } + if (bond->params.mode == BOND_MODE_8023AD) { + const struct aggregator *agg + = SLAVE_AD_INFO(slave).port.aggregator; + + if (agg) { + seq_printf(seq, "Aggregator ID: %d\n", + agg->aggregator_identifier); + } else { + seq_puts(seq, "Aggregator ID: N/A\n"); } - return ret; } +} - if (!capable(CAP_NET_ADMIN)) { - return -EPERM; +static int bond_info_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%s\n", version); + bond_info_show_master(seq); + } else { + bond_info_show_slave(seq, v); } - if (orig_app_abi_ver == -1) { - /* no orig_app_abi_ver was provided yet, so we'll use the - * current one from now on, even if it's 0 - */ - orig_app_abi_ver = app_abi_ver; + return 0; +} - } else if (orig_app_abi_ver != app_abi_ver) { - printk(KERN_ERR - "bonding: Error: already using ifenslave ABI " - "version %d; to upgrade ifenslave to version %d, " - "you must first reload bonding.\n", - orig_app_abi_ver, app_abi_ver); - return -EINVAL; +static struct seq_operations bond_info_seq_ops = { + .start = bond_info_seq_start, + .next = bond_info_seq_next, + .stop = bond_info_seq_stop, + .show = bond_info_seq_show, +}; + +static int bond_info_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + struct proc_dir_entry *proc; + int res; + + res = seq_open(file, &bond_info_seq_ops); + if (!res) { + /* recover the pointer buried in proc_dir_entry data */ + seq = file->private_data; + proc = PDE(inode); + seq->private = proc->data; } - slave_dev = dev_get_by_name(ifr->ifr_slave); + return res; +} -#ifdef BONDING_DEBUG - printk(KERN_INFO "slave_dev=%x: \n", (unsigned int)slave_dev); - printk(KERN_INFO "slave_dev->name=%s: \n", slave_dev->name); -#endif +static struct file_operations bond_info_fops = { + .owner = THIS_MODULE, + .open = bond_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - if (slave_dev == NULL) { - ret = -ENODEV; - } else { - switch (cmd) { - case BOND_ENSLAVE_OLD: - case SIOCBONDENSLAVE: - ret = bond_enslave(master_dev, slave_dev); - break; - case BOND_RELEASE_OLD: - case SIOCBONDRELEASE: - ret = bond_release(master_dev, slave_dev); - break; - case BOND_SETHWADDR_OLD: - case SIOCBONDSETHWADDR: - ret = bond_sethwaddr(master_dev, slave_dev); +static int bond_create_proc_entry(struct bonding *bond) +{ + struct net_device *bond_dev = bond->dev; + + if (bond_proc_dir) { + bond->proc_entry = create_proc_entry(bond_dev->name, + S_IRUGO, + bond_proc_dir); + if (bond->proc_entry == NULL) { + printk(KERN_WARNING DRV_NAME + ": Warning: Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); + } else { + bond->proc_entry->data = bond; + bond->proc_entry->proc_fops = &bond_info_fops; + bond->proc_entry->owner = THIS_MODULE; + memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); + } + } + + return 0; +} + +static void bond_remove_proc_entry(struct bonding *bond) +{ + if (bond_proc_dir && bond->proc_entry) { + remove_proc_entry(bond->proc_file_name, bond_proc_dir); + memset(bond->proc_file_name, 0, IFNAMSIZ); + bond->proc_entry = NULL; + } +} + +/* Create the bonding directory under /proc/net, if doesn't exist yet. + * Caller must hold rtnl_lock. + */ +static void bond_create_proc_dir(void) +{ + int len = strlen(DRV_NAME); + + for (bond_proc_dir = proc_net->subdir; bond_proc_dir; + bond_proc_dir = bond_proc_dir->next) { + if ((bond_proc_dir->namelen == len) && + !memcmp(bond_proc_dir->name, DRV_NAME, len)) { break; - case BOND_CHANGE_ACTIVE_OLD: - case SIOCBONDCHANGEACTIVE: - if (USES_PRIMARY(bond_mode)) { - ret = bond_change_active(master_dev, slave_dev); - } - else { - ret = -EINVAL; - } + } + } + + if (!bond_proc_dir) { + bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); + if (bond_proc_dir) { + bond_proc_dir->owner = THIS_MODULE; + } else { + printk(KERN_WARNING DRV_NAME + ": Warning: cannot create /proc/net/%s\n", + DRV_NAME); + } + } +} + +/* Destroy the bonding directory under /proc/net, if empty. + * Caller must hold rtnl_lock. + */ +static void bond_destroy_proc_dir(void) +{ + struct proc_dir_entry *de; + + if (!bond_proc_dir) { + return; + } + + /* verify that the /proc dir is empty */ + for (de = bond_proc_dir->subdir; de; de = de->next) { + /* ignore . and .. */ + if (*(de->name) != '.') { break; - default: - ret = -EOPNOTSUPP; } - dev_put(slave_dev); } - if (ret < 0) { - /* The ioctl failed, so there's no point in changing the - * orig_app_abi_ver. We'll restore it's value just in case - * we've changed it earlier in this function. + if (de) { + if (bond_proc_dir->owner == THIS_MODULE) { + bond_proc_dir->owner = NULL; + } + } else { + remove_proc_entry(DRV_NAME, proc_net); + bond_proc_dir = NULL; + } +} +#endif /* CONFIG_PROC_FS */ + +/*-------------------------- netdev event handling --------------------------*/ + +/* + * Change device name + */ +static int bond_event_changename(struct bonding *bond) +{ +#ifdef CONFIG_PROC_FS + bond_remove_proc_entry(bond); + bond_create_proc_entry(bond); +#endif + + return NOTIFY_DONE; +} + +static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) +{ + struct bonding *event_bond = bond_dev->priv; + + switch (event) { + case NETDEV_CHANGENAME: + return bond_event_changename(event_bond); + case NETDEV_UNREGISTER: + /* + * TODO: remove a bond from the list? */ - orig_app_abi_ver = prev_abi_ver; + break; + default: + break; } - return ret; + return NOTIFY_DONE; } -#ifdef CONFIG_NET_FASTROUTE -static int bond_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { - return -1; + struct net_device *bond_dev = slave_dev->master; + + switch (event) { + case NETDEV_UNREGISTER: + if (bond_dev) { + bond_release(bond_dev, slave_dev); + } + break; + case NETDEV_CHANGE: + /* + * TODO: is this what we get if somebody + * sets up a hierarchical bond, then rmmod's + * one of the slave bonding devices? + */ + break; + case NETDEV_DOWN: + /* + * ... Or is it this? + */ + break; + case NETDEV_CHANGEMTU: + /* + * TODO: Should slaves be allowed to + * independently alter their MTU? For + * an active-backup bond, slaves need + * not be the same type of device, so + * MTUs may vary. For other modes, + * slaves arguably should have the + * same MTUs. To do this, we'd need to + * take over the slave's change_mtu + * function for the duration of their + * servitude. + */ + break; + case NETDEV_CHANGENAME: + /* + * TODO: handle changing the primary's name + */ + break; + default: + break; + } + + return NOTIFY_DONE; } -#endif -/* - * in broadcast mode, we send everything to all usable interfaces. +/* + * bond_netdev_event: handle netdev notifier chain events. + * + * This function receives events for the netdev chain. The caller (an + * ioctl handler calling notifier_call_chain) holds the necessary + * locks for us to safely manipulate the slave devices (RTNL lock, + * dev_probe_lock). */ -static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev) +static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct net_device *device_we_should_send_to = 0; + struct net_device *event_dev = (struct net_device *)ptr; + + dprintk("event_dev: %s, event: %lx\n", + (event_dev ? event_dev->name : "None"), + event); + + if (event_dev->flags & IFF_MASTER) { + dprintk("IFF_MASTER\n"); + return bond_master_netdev_event(event, event_dev); + } - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + if (event_dev->flags & IFF_SLAVE) { + dprintk("IFF_SLAVE\n"); + return bond_slave_netdev_event(event, event_dev); } - read_lock(&bond->lock); + return NOTIFY_DONE; +} - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); +static struct notifier_block bond_netdev_notifier = { + .notifier_call = bond_netdev_event, +}; - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - read_unlock(&bond->lock); - dev_kfree_skb(skb); - return 0; - } +/*-------------------------- Packet type handling ---------------------------*/ - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - if (device_we_should_send_to) { - struct sk_buff *skb2; - if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { - printk(KERN_ERR "bond_xmit_broadcast: skb_clone() failed\n"); - continue; - } +/* register to receive lacpdus on a bond */ +static void bond_register_lacpdu(struct bonding *bond) +{ + struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type); - skb2->dev = device_we_should_send_to; - skb2->priority = 1; - dev_queue_xmit(skb2); - } - device_we_should_send_to = slave->dev; - } - } while ((slave = slave->next) != start_at); + /* initialize packet type */ + pk_type->type = PKT_TYPE_LACPDU; + pk_type->dev = bond->dev; + pk_type->func = bond_3ad_lacpdu_recv; + pk_type->data = (void*)1; /* understand shared skbs */ - if (device_we_should_send_to) { - skb->dev = device_we_should_send_to; - skb->priority = 1; - dev_queue_xmit(skb); - } else - dev_kfree_skb(skb); + dev_add_pack(pk_type); +} - /* frame sent to all suitable interfaces */ - read_unlock(&bond->lock); - return 0; +/* unregister to receive lacpdus on a bond */ +static void bond_unregister_lacpdu(struct bonding *bond) +{ + dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type)); } -static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev) +/*-------------------------- Device entry points ----------------------------*/ + +static int bond_open(struct net_device *bond_dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; + struct bonding *bond = bond_dev->priv; + struct timer_list *mii_timer = &bond->mii_timer; + struct timer_list *arp_timer = &bond->arp_timer; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } + bond->kill_timers = 0; - read_lock(&bond->lock); + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer); - read_lock(&bond->ptrlock); - slave = start_at = bond->current_slave; - read_unlock(&bond->ptrlock); + /* bond_alb_initialize must be called before the timer + * is started. + */ + if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) { + /* something went wrong - fail the open operation */ + return -1; + } - if (slave == NULL) { /* we're at the root, get the first slave */ - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + init_timer(alb_timer); + alb_timer->expires = jiffies + 1; + alb_timer->data = (unsigned long)bond; + alb_timer->function = (void *)&bond_alb_monitor; + add_timer(alb_timer); } - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); - - write_lock(&bond->ptrlock); - bond->current_slave = slave->next; - write_unlock(&bond->ptrlock); + if (bond->params.miimon) { /* link check interval, in milliseconds. */ + init_timer(mii_timer); + mii_timer->expires = jiffies + 1; + mii_timer->data = (unsigned long)bond_dev; + mii_timer->function = (void *)&bond_mii_monitor; + add_timer(mii_timer); + } - read_unlock(&bond->lock); - return 0; + if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ + init_timer(arp_timer); + arp_timer->expires = jiffies + 1; + arp_timer->data = (unsigned long)bond_dev; + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + arp_timer->function = (void *)&bond_activebackup_arp_mon; + } else { + arp_timer->function = (void *)&bond_loadbalance_arp_mon; } - } while ((slave = slave->next) != start_at); + add_timer(arp_timer); + } + + if (bond->params.mode == BOND_MODE_8023AD) { + struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer); + init_timer(ad_timer); + ad_timer->expires = jiffies + 1; + ad_timer->data = (unsigned long)bond; + ad_timer->function = (void *)&bond_3ad_state_machine_handler; + add_timer(ad_timer); + + /* register to receive LACPDUs */ + bond_register_lacpdu(bond); + } - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); return 0; } -/* - * in XOR mode, we determine the output device by performing xor on - * the source and destination hw adresses. If this device is not - * enabled, find the next slave following this xor slave. - */ -static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev) +static int bond_close(struct net_device *bond_dev) { - slave_t *slave, *start_at; - struct bonding *bond = (struct bonding *) dev->priv; - struct ethhdr *data = (struct ethhdr *)skb->data; - int slave_no; + struct bonding *bond = bond_dev->priv; - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; - } + write_lock_bh(&bond->lock); - read_lock(&bond->lock); - slave = bond->prev; + bond_mc_list_destroy(bond); - /* we're at the root, get the first slave */ - if (bond->slave_cnt == 0) { - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; + if (bond->params.mode == BOND_MODE_8023AD) { + /* Unregister the receive of LACPDUs */ + bond_unregister_lacpdu(bond); } - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; - - while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { - slave = slave->prev; - slave_no--; - } - start_at = slave; - - do { - if (IS_UP(slave->dev) - && (slave->link == BOND_LINK_UP) - && (slave->state == BOND_STATE_ACTIVE)) { - - skb->dev = slave->dev; - skb->priority = 1; - dev_queue_xmit(skb); - - read_unlock(&bond->lock); - return 0; - } - } while ((slave = slave->next) != start_at); + /* signal timers not to re-arm */ + bond->kill_timers = 1; - /* no suitable interface, frame not sent */ - dev_kfree_skb(skb); - read_unlock(&bond->lock); - return 0; -} + write_unlock_bh(&bond->lock); -/* - * in active-backup mode, we know that bond->current_slave is always valid if - * the bond has a usable interface. - */ -static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev) -{ - struct bonding *bond = (struct bonding *) dev->priv; - int ret; + /* del_timer_sync must run without holding the bond->lock + * because a running timer might be trying to hold it too + */ - if (!IS_UP(dev)) { /* bond down */ - dev_kfree_skb(skb); - return 0; + if (bond->params.miimon) { /* link check interval, in milliseconds. */ + del_timer_sync(&bond->mii_timer); } - /* if we are sending arp packets, try to at least - identify our own ip address */ - if ( (arp_interval > 0) && (my_ip == 0) && - (skb->protocol == __constant_htons(ETH_P_ARP) ) ) { - char *the_ip = (((char *)skb->data)) - + sizeof(struct ethhdr) - + sizeof(struct arphdr) + - ETH_ALEN; - memcpy(&my_ip, the_ip, 4); + if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ + del_timer_sync(&bond->arp_timer); } - /* if we are sending arp packets and don't know - * the target hw address, save it so we don't need - * to use a broadcast address. - * don't do this if in active backup mode because the slaves must - * receive packets to stay up, and the only ones they receive are - * broadcasts. - */ - if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && - (arp_ip_count == 1) && - (arp_interval > 0) && (arp_target_hw_addr == NULL) && - (skb->protocol == __constant_htons(ETH_P_IP) ) ) { - struct ethhdr *eth_hdr = - (struct ethhdr *) (((char *)skb->data)); - struct iphdr *ip_hdr = (struct iphdr *)(eth_hdr + 1); - - if (arp_target[0] == ip_hdr->daddr) { - arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL); - if (arp_target_hw_addr != NULL) - memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN); - } + switch (bond->params.mode) { + case BOND_MODE_8023AD: + del_timer_sync(&(BOND_AD_INFO(bond).ad_timer)); + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: + del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer)); + break; + default: + break; } - read_lock(&bond->lock); + /* Release the bonded slaves */ + bond_release_all(bond_dev); - read_lock(&bond->ptrlock); - if (bond->current_slave != NULL) { /* one usable interface */ - skb->dev = bond->current_slave->dev; - read_unlock(&bond->ptrlock); - skb->priority = 1; - ret = dev_queue_xmit(skb); - read_unlock(&bond->lock); - return 0; - } - else { - read_unlock(&bond->ptrlock); + if ((bond->params.mode == BOND_MODE_TLB) || + (bond->params.mode == BOND_MODE_ALB)) { + /* Must be called only after all + * slaves have been released + */ + bond_alb_deinitialize(bond); } - /* no suitable interface, frame not sent */ -#ifdef BONDING_DEBUG - printk(KERN_INFO "There was no suitable interface, so we don't transmit\n"); -#endif - dev_kfree_skb(skb); - read_unlock(&bond->lock); return 0; } -static struct net_device_stats *bond_get_stats(struct net_device *dev) +static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { - bonding_t *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct net_device_stats *stats = &(bond->stats), *sstats; - slave_t *slave; + struct slave *slave; + int i; memset(stats, 0, sizeof(struct net_device_stats)); read_lock_bh(&bond->lock); - for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) { + bond_for_each_slave(bond, slave, i) { sstats = slave->dev->get_stats(slave->dev); - + stats->rx_packets += sstats->rx_packets; stats->rx_bytes += sstats->rx_bytes; stats->rx_errors += sstats->rx_errors; @@ -3347,290 +3650,290 @@ stats->rx_over_errors += sstats->rx_over_errors; stats->rx_crc_errors += sstats->rx_crc_errors; stats->rx_frame_errors += sstats->rx_frame_errors; - stats->rx_fifo_errors += sstats->rx_fifo_errors; + stats->rx_fifo_errors += sstats->rx_fifo_errors; stats->rx_missed_errors += sstats->rx_missed_errors; - + stats->tx_aborted_errors += sstats->tx_aborted_errors; stats->tx_carrier_errors += sstats->tx_carrier_errors; stats->tx_fifo_errors += sstats->tx_fifo_errors; stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; stats->tx_window_errors += sstats->tx_window_errors; - } read_unlock_bh(&bond->lock); + return stats; } -#ifdef CONFIG_PROC_FS - -#define SEQ_START_TOKEN ((void *)1) - -static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) +static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) { - struct bonding *bond = seq->private; - loff_t off = 0; - struct slave *slave; - - /* make sure the bond won't be taken away */ - read_lock(&dev_base_lock); - read_lock_bh(&bond->lock); - - if (*pos == 0) { - return SEQ_START_TOKEN; - } + struct net_device *slave_dev = NULL; + struct ifbond *u_binfo = NULL, k_binfo; + struct ifslave *u_sinfo = NULL, k_sinfo; + struct mii_ioctl_data *mii = NULL; + int prev_abi_ver = orig_app_abi_ver; + int res = 0; - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { + dprintk("bond_ioctl: master=%s, cmd=%d\n", + bond_dev->name, cmd); - if (++off == *pos) { - return slave; + switch (cmd) { + case SIOCETHTOOL: + return bond_ethtool_ioctl(bond_dev, ifr); + case SIOCGMIIPHY: + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; + } + mii->phy_id = 0; + /* Fall Through */ + case SIOCGMIIREG: + /* + * We do this again just in case we were called by SIOCGMIIREG + * instead of SIOCGMIIPHY. + */ + mii = (struct mii_ioctl_data *)&ifr->ifr_data; + if (!mii) { + return -EINVAL; } - } - - return NULL; -} - -static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct bonding *bond = seq->private; - struct slave *slave = v; - - ++*pos; - if (v == SEQ_START_TOKEN) { - slave = bond->prev; - } else { - slave = slave->prev; - } - - return (slave == (struct slave *) bond) ? NULL : slave; -} -static void bond_info_seq_stop(struct seq_file *seq, void *v) -{ - struct bonding *bond = seq->private; + if (mii->reg_num == 1) { + struct bonding *bond = bond_dev->priv; + mii->val_out = 0; + read_lock_bh(&bond->lock); + read_lock(&bond->curr_slave_lock); + if (bond->curr_active_slave) { + mii->val_out = BMSR_LSTATUS; + } + read_unlock(&bond->curr_slave_lock); + read_unlock_bh(&bond->lock); + } - read_unlock_bh(&bond->lock); - read_unlock(&dev_base_lock); -} + return 0; + case BOND_INFO_QUERY_OLD: + case SIOCBONDINFOQUERY: + u_binfo = (struct ifbond *)ifr->ifr_data; -static void bond_info_show_master(struct seq_file *seq, struct bonding *bond) -{ - struct slave *curr; + if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) { + return -EFAULT; + } - read_lock(&bond->ptrlock); - curr = bond->current_slave; - read_unlock(&bond->ptrlock); - - seq_printf(seq, "Bonding Mode: %s\n", bond_mode_name()); - - if (USES_PRIMARY(bond_mode)) { - if (curr) { - seq_printf(seq, - "Currently Active Slave: %s\n", - curr->dev->name); + res = bond_info_query(bond_dev, &k_binfo); + if (res == 0) { + if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) { + return -EFAULT; + } } - } - seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); - seq_printf(seq, "MII Polling Interval (ms): %d\n", miimon); - seq_printf(seq, "Up Delay (ms): %d\n", updelay * miimon); - seq_printf(seq, "Down Delay (ms): %d\n", downdelay * miimon); - seq_printf(seq, "Multicast Mode: %s\n", multicast_mode_name()); + return res; + case BOND_SLAVE_INFO_QUERY_OLD: + case SIOCBONDSLAVEINFOQUERY: + u_sinfo = (struct ifslave *)ifr->ifr_data; - if (bond_mode == BOND_MODE_8023AD) { - struct ad_info ad_info; + if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) { + return -EFAULT; + } - seq_puts(seq, "\n802.3ad info\n"); + res = bond_slave_info_query(bond_dev, &k_sinfo); + if (res == 0) { + if (copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) { + return -EFAULT; + } + } - if (bond_3ad_get_active_agg_info(bond, &ad_info)) { - seq_printf(seq, "bond %s has no active aggregator\n", - bond->device->name); - } else { - seq_printf(seq, "Active Aggregator Info:\n"); + return res; + default: + /* Go on */ + break; + } - seq_printf(seq, "\tAggregator ID: %d\n", - ad_info.aggregator_id); - seq_printf(seq, "\tNumber of ports: %d\n", - ad_info.ports); - seq_printf(seq, "\tActor Key: %d\n", - ad_info.actor_key); - seq_printf(seq, "\tPartner Key: %d\n", - ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - ad_info.partner_system[0], - ad_info.partner_system[1], - ad_info.partner_system[2], - ad_info.partner_system[3], - ad_info.partner_system[4], - ad_info.partner_system[5]); - } + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; } -} -static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) -{ - seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); - seq_printf(seq, "MII Status: %s\n", - (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Link Failure Count: %d\n", - slave->link_failure_count); + if (orig_app_abi_ver == -1) { + /* no orig_app_abi_ver was provided yet, so we'll use the + * current one from now on, even if it's 0 + */ + orig_app_abi_ver = app_abi_ver; - if (app_abi_ver >= 1) { - seq_printf(seq, - "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n", - slave->perm_hwaddr[0], - slave->perm_hwaddr[1], - slave->perm_hwaddr[2], - slave->perm_hwaddr[3], - slave->perm_hwaddr[4], - slave->perm_hwaddr[5]); + } else if (orig_app_abi_ver != app_abi_ver) { + printk(KERN_ERR DRV_NAME + ": Error: already using ifenslave ABI version %d; to " + "upgrade ifenslave to version %d, you must first " + "reload bonding.\n", + orig_app_abi_ver, app_abi_ver); + return -EINVAL; } - if (bond_mode == BOND_MODE_8023AD) { - const struct aggregator *agg - = SLAVE_AD_INFO(slave).port.aggregator; + slave_dev = dev_get_by_name(ifr->ifr_slave); - if (agg) { - seq_printf(seq, "Aggregator ID: %d\n", - agg->aggregator_identifier); - } else { - seq_puts(seq, "Aggregator ID: N/A\n"); + dprintk("slave_dev=%p: \n", slave_dev); + + if (!slave_dev) { + res = -ENODEV; + } else { + dprintk("slave_dev->name=%s: \n", slave_dev->name); + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + res = bond_enslave(bond_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + res = bond_release(bond_dev, slave_dev); + break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + res = bond_sethwaddr(bond_dev, slave_dev); + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + res = bond_ioctl_change_active(bond_dev, slave_dev); + break; + default: + res = -EOPNOTSUPP; } + + dev_put(slave_dev); } -} -static int bond_info_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "%s\n", version); - bond_info_show_master(seq, seq->private); - } else { - bond_info_show_slave(seq, v); + if (res < 0) { + /* The ioctl failed, so there's no point in changing the + * orig_app_abi_ver. We'll restore it's value just in case + * we've changed it earlier in this function. + */ + orig_app_abi_ver = prev_abi_ver; } - return 0; + return res; } -static struct seq_operations bond_info_seq_ops = { - .start = bond_info_seq_start, - .next = bond_info_seq_next, - .stop = bond_info_seq_stop, - .show = bond_info_seq_show, -}; - -static int bond_info_open(struct inode *inode, struct file *file) +static void bond_set_multicast_list(struct net_device *bond_dev) { - struct seq_file *seq; - struct proc_dir_entry *proc; - int rc; - - rc = seq_open(file, &bond_info_seq_ops); - if (!rc) { - /* recover the pointer buried in proc_dir_entry data */ - seq = file->private_data; - proc = PDE(inode); - seq->private = proc->data; - } - return rc; -} + struct bonding *bond = bond_dev->priv; + struct dev_mc_list *dmi; -static struct file_operations bond_info_fops = { - .owner = THIS_MODULE, - .open = bond_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; + write_lock_bh(&bond->lock); -static int bond_create_proc_info(struct bonding *bond) -{ - struct net_device *dev = bond->device; + /* + * Do promisc before checking multicast_mode + */ + if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, 1); + } - if (bond_proc_dir) { - bond->bond_proc_file = create_proc_entry(dev->name, - S_IRUGO, - bond_proc_dir); - if (bond->bond_proc_file == NULL) { - printk(KERN_WARNING - "%s: Cannot create /proc/net/bonding/%s\n", - dev->name, dev->name); - } else { - bond->bond_proc_file->data = bond; - bond->bond_proc_file->proc_fops = &bond_info_fops; - bond->bond_proc_file->owner = THIS_MODULE; - memcpy(bond->procdir_name, dev->name, IFNAMSIZ); - } + if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC)) { + bond_set_promiscuity(bond, -1); } - return 0; -} + /* set allmulti flag to slaves */ + if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, 1); + } -static void bond_destroy_proc_info(struct bonding *bond) -{ - if (bond_proc_dir && bond->bond_proc_file) { - remove_proc_entry(bond->procdir_name, bond_proc_dir); - memset(bond->procdir_name, 0, IFNAMSIZ); - bond->bond_proc_file = NULL; + if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI)) { + bond_set_allmulti(bond, -1); } -} -/* Create the bonding directory under /proc/net, if doesn't exist yet. - * Caller must hold rtnl_lock. - */ -static void bond_create_proc_dir(void) -{ - int len = strlen(DRV_NAME); + bond->flags = bond_dev->flags; - for (bond_proc_dir = proc_net->subdir; bond_proc_dir; - bond_proc_dir = bond_proc_dir->next) { - if ((bond_proc_dir->namelen == len) && - !memcmp(bond_proc_dir->name, DRV_NAME, len)) { - break; + /* looking for addresses to add to slaves' mc list */ + for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond->mc_list)) { + bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } - if (!bond_proc_dir) { - bond_proc_dir = proc_mkdir(DRV_NAME, proc_net); - if (bond_proc_dir) { - bond_proc_dir->owner = THIS_MODULE; - } else { - printk(KERN_WARNING DRV_NAME - ": Warning: cannot create /proc/net/%s\n", - DRV_NAME); + /* looking for addresses to delete from slaves' list */ + for (dmi = bond->mc_list; dmi; dmi = dmi->next) { + if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list)) { + bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); } } + + /* save master's multicast list */ + bond_mc_list_destroy(bond); + bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC); + + write_unlock_bh(&bond->lock); } -/* Destroy the bonding directory under /proc/net, if empty. - * Caller must hold rtnl_lock. +/* + * Change the MTU of all of a master's slaves to match the master */ -static void bond_destroy_proc_dir(void) +static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct proc_dir_entry *de; + struct bonding *bond = bond_dev->priv; + struct slave *slave, *stop_at; + int res = 0; + int i; - if (!bond_proc_dir) { - return; - } + dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + (bond_dev ? bond_dev->name : "None"), new_mtu); - /* verify that the /proc dir is empty */ - for (de = bond_proc_dir->subdir; de; de = de->next) { - /* ignore . and .. */ - if (*(de->name) != '.') { - break; + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's MTU while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("s %p s->p %p c_m %p\n", slave, + slave->prev, slave->dev->change_mtu); + if (slave->dev->change_mtu) { + res = slave->dev->change_mtu(slave->dev, new_mtu); + } else { + slave->dev->mtu = new_mtu; + res = 0; + } + + if (res) { + /* If we failed to set the slave's mtu to the new value + * we must abort the operation even in ACTIVE_BACKUP + * mode, because if we allow the backup slaves to have + * different mtu values than the active slave we'll + * need to change their mtu when doing a failover. That + * means changing their mtu from timer context, which + * is probably not a good idea. + */ + dprintk("err %d %s\n", res, slave->dev->name); + goto unwind; } } - if (de) { - if (bond_proc_dir->owner == THIS_MODULE) { - bond_proc_dir->owner = NULL; + bond_dev->mtu = new_mtu; + + return 0; + +unwind: + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + if (slave->dev->change_mtu) { + tmp_res = slave->dev->change_mtu(slave->dev, bond_dev->mtu); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } else { + slave->dev->mtu = bond_dev->mtu; } - } else { - remove_proc_entry(DRV_NAME, proc_net); - bond_proc_dir = NULL; } + + return res; } -#endif /* CONFIG_PROC_FS */ /* * Change HW address @@ -3639,263 +3942,404 @@ * downing the master releases all slaves. We can make bonds full of * bonding devices to test this, however. */ -static inline int -bond_set_mac_address(struct net_device *dev, void *addr) +static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; struct sockaddr *sa = addr, tmp_sa; - struct slave *slave; - int error; + struct slave *slave, *stop_at; + int res = 0; + int i; - dprintk(KERN_INFO "bond_set_mac_address %p %s\n", dev, - dev->name); + dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); if (!is_valid_ether_addr(sa->sa_data)) { return -EADDRNOTAVAIL; } - for (slave = bond->prev; slave != (struct slave *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "bond_set_mac: slave %p %s\n", slave, - slave->dev->name); + /* Can't hold bond->lock with bh disabled here since + * some base drivers panic. On the other hand we can't + * hold bond->lock without bh disabled because we'll + * deadlock. The only solution is to rely on the fact + * that we're under rtnl_lock here, and the slaves + * list won't change. This doesn't solve the problem + * of setting the slave's hw address while it is + * transmitting, but the assumption is that the base + * driver can handle that. + * + * TODO: figure out a way to safely iterate the slaves + * list, but without holding a lock around the actual + * call to the base driver. + */ + + bond_for_each_slave(bond, slave, i) { + dprintk("slave %p %s\n", slave, slave->dev->name); + if (slave->dev->set_mac_address == NULL) { - error = -EOPNOTSUPP; - dprintk(KERN_INFO "bond_set_mac EOPNOTSUPP %s\n", - slave->dev->name); + res = -EOPNOTSUPP; + dprintk("EOPNOTSUPP %s\n", slave->dev->name); goto unwind; } - error = slave->dev->set_mac_address(slave->dev, addr); - if (error) { - /* TODO: consider downing the slave + res = slave->dev->set_mac_address(slave->dev, addr); + if (res) { + /* TODO: consider downing the slave * and retry ? * User should expect communications * breakage anyway until ARP finish * updating, so... */ - dprintk(KERN_INFO "bond_set_mac err %d %s\n", - error, slave->dev->name); + dprintk("err %d %s\n", res, slave->dev->name); goto unwind; } } /* success */ - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); return 0; unwind: - memcpy(tmp_sa.sa_data, dev->dev_addr, dev->addr_len); - tmp_sa.sa_family = dev->type; + memcpy(tmp_sa.sa_data, bond_dev->dev_addr, bond_dev->addr_len); + tmp_sa.sa_family = bond_dev->type; + + /* unwind from head to the slave that failed */ + stop_at = slave; + bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) { + int tmp_res; + + tmp_res = slave->dev->set_mac_address(slave->dev, &tmp_sa); + if (tmp_res) { + dprintk("unwind err %d dev %s\n", tmp_res, + slave->dev->name); + } + } + + return res; +} + +static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + int i; + int res = 1; + + read_lock(&bond->lock); + + if (!BOND_IS_OK(bond)) { + goto out; + } + + read_lock(&bond->curr_slave_lock); + slave = start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!slave) { + goto out; + } - for (slave = slave->next; slave != bond->next; - slave = slave->next) { - int tmp_error; + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + res = bond_dev_queue_xmit(bond, skb, slave->dev); + + write_lock(&bond->curr_slave_lock); + bond->curr_active_slave = slave->next; + write_unlock(&bond->curr_slave_lock); - tmp_error = slave->dev->set_mac_address(slave->dev, &tmp_sa); - if (tmp_error) { - dprintk(KERN_INFO "bond_set_mac_address: " - "unwind err %d dev %s\n", - tmp_error, slave->dev->name); + break; } } - return error; + +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } + read_unlock(&bond->lock); + return 0; } /* - * Change the MTU of all of a master's slaves to match the master + * in active-backup mode, we know that bond->curr_active_slave is always valid if + * the bond has a usable interface. */ -static inline int -bond_change_mtu(struct net_device *dev, int newmtu) +static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { - bonding_t *bond = dev->priv; - slave_t *slave; - int error; - - dprintk(KERN_INFO "CM: b %p nm %d\n", bond, newmtu); - for (slave = bond->prev; slave != (slave_t *)bond; - slave = slave->prev) { - dprintk(KERN_INFO "CM: s %p s->p %p c_m %p\n", slave, - slave->prev, slave->dev->change_mtu); - if (slave->dev->change_mtu) { - error = slave->dev->change_mtu(slave->dev, newmtu); - } else { - slave->dev->mtu = newmtu; - error = 0; - } + struct bonding *bond = bond_dev->priv; + int res = 1; - if (error) { - /* If we failed to set the slave's mtu to the new value - * we must abort the operation even in ACTIVE_BACKUP - * mode, because if we allow the backup slaves to have - * different mtu values than the active slave we'll - * need to change their mtu when doing a failover. That - * means changing their mtu from timer context, which - * is probably not a good idea. - */ - dprintk(KERN_INFO "bond_change_mtu err %d %s\n", - error, slave->dev->name); - goto unwind; - } + /* if we are sending arp packets, try to at least + identify our own ip address */ + if (bond->params.arp_interval && !my_ip && + (skb->protocol == __constant_htons(ETH_P_ARP))) { + char *the_ip = (char *)skb->data + + sizeof(struct ethhdr) + + sizeof(struct arphdr) + + ETH_ALEN; + memcpy(&my_ip, the_ip, 4); } - dev->mtu = newmtu; + read_lock(&bond->lock); + read_lock(&bond->curr_slave_lock); + + if (!BOND_IS_OK(bond)) { + goto out; + } + + if (bond->curr_active_slave) { /* one usable interface */ + res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); + } + +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } + read_unlock(&bond->curr_slave_lock); + read_unlock(&bond->lock); return 0; +} +/* + * in XOR mode, we determine the output device by performing xor on + * the source and destination hw adresses. If this device is not + * enabled, find the next slave following this xor slave. + */ +static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) +{ + struct bonding *bond = bond_dev->priv; + struct ethhdr *data = (struct ethhdr *)skb->data; + struct slave *slave, *start_at; + int slave_no; + int i; + int res = 1; -unwind: - for (slave = slave->next; slave != bond->next; - slave = slave->next) { + read_lock(&bond->lock); - if (slave->dev->change_mtu) { - slave->dev->change_mtu(slave->dev, dev->mtu); - } else { - slave->dev->mtu = dev->mtu; + if (!BOND_IS_OK(bond)) { + goto out; + } + + slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt; + + bond_for_each_slave(bond, slave, i) { + slave_no--; + if (slave_no < 0) { + break; + } + } + + start_at = slave; + + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + res = bond_dev_queue_xmit(bond, skb, slave->dev); + break; } } - return error; +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } + read_unlock(&bond->lock); + return 0; } /* - * Change device name + * in broadcast mode, we send everything to all usable interfaces. */ -static inline int bond_event_changename(struct bonding *bond) +static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { -#ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); - bond_create_proc_info(bond); -#endif + struct bonding *bond = bond_dev->priv; + struct slave *slave, *start_at; + struct net_device *tx_dev = NULL; + int i; + int res = 1; - return NOTIFY_DONE; -} + read_lock(&bond->lock); -static int bond_master_netdev_event(unsigned long event, struct net_device *event_dev) -{ - struct bonding *bond, *event_bond = NULL; + if (!BOND_IS_OK(bond)) { + goto out; + } - list_for_each_entry(bond, &bond_dev_list, bond_list) { - if (bond == event_dev->priv) { - event_bond = bond; - break; - } + read_lock(&bond->curr_slave_lock); + start_at = bond->curr_active_slave; + read_unlock(&bond->curr_slave_lock); + + if (!start_at) { + goto out; } - if (event_bond == NULL) { - return NOTIFY_DONE; + bond_for_each_slave_from(bond, slave, i, start_at) { + if (IS_UP(slave->dev) && + (slave->link == BOND_LINK_UP) && + (slave->state == BOND_STATE_ACTIVE)) { + if (tx_dev) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + printk(KERN_ERR DRV_NAME + ": Error: bond_xmit_broadcast(): " + "skb_clone() failed\n"); + continue; + } + + res = bond_dev_queue_xmit(bond, skb2, tx_dev); + if (res) { + dev_kfree_skb(skb2); + continue; + } + } + tx_dev = slave->dev; + } } - switch (event) { - case NETDEV_CHANGENAME: - return bond_event_changename(event_bond); - case NETDEV_UNREGISTER: - /* - * TODO: remove a bond from the list? - */ - break; - default: - break; + if (tx_dev) { + res = bond_dev_queue_xmit(bond, skb, tx_dev); } - return NOTIFY_DONE; +out: + if (res) { + /* no suitable interface, frame not sent */ + dev_kfree_skb(skb); + } + /* frame sent to all suitable interfaces */ + read_unlock(&bond->lock); + return 0; } -static int bond_slave_netdev_event(unsigned long event, struct net_device *event_dev) +#ifdef CONFIG_NET_FASTROUTE +static int bond_accept_fastpath(struct net_device *bond_dev, struct dst_entry *dst) { - struct net_device *master = event_dev->master; + return -1; +} +#endif - switch (event) { - case NETDEV_UNREGISTER: - if (master != NULL) { - bond_release(master, event_dev); - } +/*------------------------- Device initialization ---------------------------*/ + +/* + * set bond mode specific net device operations + */ +static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode) +{ + switch (mode) { + case BOND_MODE_ROUNDROBIN: + bond_dev->hard_start_xmit = bond_xmit_roundrobin; break; - case NETDEV_CHANGE: - /* - * TODO: is this what we get if somebody - * sets up a hierarchical bond, then rmmod's - * one of the slave bonding devices? - */ + case BOND_MODE_ACTIVEBACKUP: + bond_dev->hard_start_xmit = bond_xmit_activebackup; break; - case NETDEV_DOWN: - /* - * ... Or is it this? - */ + case BOND_MODE_XOR: + bond_dev->hard_start_xmit = bond_xmit_xor; break; - case NETDEV_CHANGEMTU: - /* - * TODO: Should slaves be allowed to - * independently alter their MTU? For - * an active-backup bond, slaves need - * not be the same type of device, so - * MTUs may vary. For other modes, - * slaves arguably should have the - * same MTUs. To do this, we'd need to - * take over the slave's change_mtu - * function for the duration of their - * servitude. - */ + case BOND_MODE_BROADCAST: + bond_dev->hard_start_xmit = bond_xmit_broadcast; break; - case NETDEV_CHANGENAME: - /* - * TODO: handle changing the primary's name - */ + case BOND_MODE_8023AD: + bond_dev->hard_start_xmit = bond_3ad_xmit_xor; + break; + case BOND_MODE_TLB: + case BOND_MODE_ALB: + bond_dev->hard_start_xmit = bond_alb_xmit; + bond_dev->set_mac_address = bond_alb_set_mac_address; break; default: + /* Should never happen, mode already checked */ + printk(KERN_ERR DRV_NAME + ": Error: Unknown bonding mode %d\n", + mode); break; } - - return NOTIFY_DONE; } /* - * bond_netdev_event: handle netdev notifier chain events. - * - * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary - * locks for us to safely manipulate the slave devices (RTNL lock, - * dev_probe_lock). + * Does not allocate but creates a /proc entry. + * Allowed to fail. */ -static int bond_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) +static int __init bond_init(struct net_device *bond_dev, struct bond_params *params) { - struct net_device *event_dev = (struct net_device *)ptr; - unsigned short flags; - int res = NOTIFY_DONE; + struct bonding *bond = bond_dev->priv; - dprintk(KERN_INFO "bond_netdev_event n_b %p ev %lx ptr %p\n", - this, event, ptr); + dprintk("Begin bond_init for %s\n", bond_dev->name); - flags = event_dev->flags & (IFF_MASTER | IFF_SLAVE); - switch (flags) { - case IFF_MASTER: - res = bond_master_netdev_event(event, event_dev); - break; - case IFF_SLAVE: - res = bond_slave_netdev_event(event, event_dev); - break; - default: - /* A master that is also a slave ? */ - break; - } + /* initialize rwlocks */ + rwlock_init(&bond->lock); + rwlock_init(&bond->curr_slave_lock); - return res; -} + bond->params = *params; /* copy params struct */ -static struct notifier_block bond_netdev_notifier = { - .notifier_call = bond_netdev_event, -}; + /* Initialize pointers */ + bond->first_slave = NULL; + bond->curr_active_slave = NULL; + bond->current_arp_slave = NULL; + bond->primary_slave = NULL; + bond->dev = bond_dev; + INIT_LIST_HEAD(&bond->vlan_list); + + /* Initialize the device entry points */ + bond_dev->open = bond_open; + bond_dev->stop = bond_close; + bond_dev->get_stats = bond_get_stats; + bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->set_multicast_list = bond_set_multicast_list; + bond_dev->change_mtu = bond_change_mtu; + bond_dev->set_mac_address = bond_set_mac_address; + + bond_set_mode_ops(bond_dev, bond->params.mode); + +#ifdef CONFIG_NET_FASTROUTE + bond_dev->accept_fastpath = bond_accept_fastpath; +#endif + + /* Initialize the device options */ + bond_dev->tx_queue_len = 0; + bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; + + /* At first, we block adding VLANs. That's the only way to + * prevent problems that occur when adding VLANs over an + * empty bond. The block will be removed once non-challenged + * slaves are enslaved. + */ + bond_dev->features |= NETIF_F_VLAN_CHALLENGED; + + /* By default, we declare the bond to be fully + * VLAN hardware accelerated capable. Special + * care is taken in the various xmit functions + * when there are slaves that are not hw accel + * capable + */ + bond_dev->vlan_rx_register = bond_vlan_rx_register; + bond_dev->vlan_rx_add_vid = bond_vlan_rx_add_vid; + bond_dev->vlan_rx_kill_vid = bond_vlan_rx_kill_vid; + bond_dev->features |= (NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER); + +#ifdef CONFIG_PROC_FS + bond_create_proc_entry(bond); +#endif + + list_add_tail(&bond->bond_list, &bond_dev_list); + + return 0; +} /* De-initialize device specific data. * Caller must hold rtnl_lock. */ -static inline void bond_deinit(struct net_device *dev) +static inline void bond_deinit(struct net_device *bond_dev) { - struct bonding *bond = dev->priv; + struct bonding *bond = bond_dev->priv; list_del(&bond->bond_list); #ifdef CONFIG_PROC_FS - bond_destroy_proc_info(bond); + bond_remove_proc_entry(bond); #endif } @@ -3907,11 +4351,11 @@ struct bonding *bond, *nxt; list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { - struct net_device *dev = bond->device; + struct net_device *bond_dev = bond->dev; - unregister_netdevice(dev); - bond_deinit(dev); - free_netdev(dev); + unregister_netdevice(bond_dev); + bond_deinit(bond_dev); + free_netdev(bond_dev); } #ifdef CONFIG_PROC_FS @@ -3919,123 +4363,21 @@ #endif } -/* - * Does not allocate but creates a /proc entry. - * Allowed to fail. - */ -static int __init bond_init(struct net_device *dev) -{ - struct bonding *bond; - int count; - -#ifdef BONDING_DEBUG - printk (KERN_INFO "Begin bond_init for %s\n", dev->name); -#endif - bond = dev->priv; - - /* initialize rwlocks */ - rwlock_init(&bond->lock); - rwlock_init(&bond->ptrlock); - - /* Initialize pointers */ - bond->next = bond->prev = (slave_t *)bond; - bond->current_slave = NULL; - bond->current_arp_slave = NULL; - bond->device = dev; - - /* Initialize the device structure. */ - dev->set_mac_address = bond_set_mac_address; - - switch (bond_mode) { - case BOND_MODE_ACTIVEBACKUP: - dev->hard_start_xmit = bond_xmit_activebackup; - break; - case BOND_MODE_ROUNDROBIN: - dev->hard_start_xmit = bond_xmit_roundrobin; - break; - case BOND_MODE_XOR: - dev->hard_start_xmit = bond_xmit_xor; - break; - case BOND_MODE_BROADCAST: - dev->hard_start_xmit = bond_xmit_broadcast; - break; - case BOND_MODE_8023AD: - dev->hard_start_xmit = bond_3ad_xmit_xor; - break; - case BOND_MODE_TLB: - case BOND_MODE_ALB: - dev->hard_start_xmit = bond_alb_xmit; - dev->set_mac_address = bond_alb_set_mac_address; - break; - default: - printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); - return -EINVAL; - } - - dev->get_stats = bond_get_stats; - dev->open = bond_open; - dev->stop = bond_close; - dev->set_multicast_list = set_multicast_list; - dev->do_ioctl = bond_ioctl; - dev->change_mtu = bond_change_mtu; - dev->tx_queue_len = 0; - dev->flags |= IFF_MASTER|IFF_MULTICAST; -#ifdef CONFIG_NET_FASTROUTE - dev->accept_fastpath = bond_accept_fastpath; -#endif - - printk(KERN_INFO "%s registered with", dev->name); - if (miimon > 0) { - printk(" MII link monitoring set to %d ms", miimon); - updelay /= miimon; - downdelay /= miimon; - } else { - printk("out MII link monitoring"); - } - printk(", in %s mode.\n", bond_mode_name()); - - printk(KERN_INFO "%s registered with", dev->name); - if (arp_interval > 0) { - printk(" ARP monitoring set to %d ms with %d target(s):", - arp_interval, arp_ip_count); - for (count=0 ; countbond_list, &bond_dev_list); - - return 0; -} - -/* -static int __init bond_probe(struct net_device *dev) -{ - bond_init(dev); - return 0; -} - */ +/*------------------------- Module initialization ---------------------------*/ /* * Convert string input module parms. Accept either the * number of the mode or its string name. */ -static inline int -bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +static inline int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) { int i; - for (i = 0; tbl[i].modename != NULL; i++) { + for (i = 0; tbl[i].modename; i++) { if ((isdigit(*mode_arg) && - tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (0 == strncmp(mode_arg, tbl[i].modename, - strlen(tbl[i].modename)))) { + tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || + (strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)) == 0)) { return tbl[i].mode; } } @@ -4043,275 +4385,281 @@ return -1; } - -static int __init bonding_init(void) +static int bond_check_params(struct bond_params *params) { - int no; - int err; - - printk(KERN_INFO "%s", version); - /* * Convert string parameters. */ if (mode) { bond_mode = bond_parse_parm(mode, bond_mode_tbl); if (bond_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid bonding mode \"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid bonding mode \"%s\"\n", mode == NULL ? "NULL" : mode); return -EINVAL; } } - if (USES_PRIMARY(bond_mode)) { - multicast_mode = BOND_MULTICAST_ACTIVE; - } else { - multicast_mode = BOND_MULTICAST_ALL; - } - - if (multicast) { - multicast_mode = bond_parse_parm(multicast, bond_mc_tbl); - if (multicast_mode == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid multicast mode \"%s\"\n", - multicast == NULL ? "NULL" : multicast); - return -EINVAL; - } - } - if (lacp_rate) { if (bond_mode != BOND_MODE_8023AD) { - printk(KERN_WARNING - "lacp_rate param is irrelevant in mode %s\n", - bond_mode_name()); + printk(KERN_INFO DRV_NAME + ": lacp_rate param is irrelevant in mode %s\n", + bond_mode_name(bond_mode)); } else { lacp_fast = bond_parse_parm(lacp_rate, bond_lacp_tbl); if (lacp_fast == -1) { - printk(KERN_WARNING - "bonding_init(): Invalid lacp rate " - "\"%s\"\n", + printk(KERN_ERR DRV_NAME + ": Error: Invalid lacp rate \"%s\"\n", lacp_rate == NULL ? "NULL" : lacp_rate); - return -EINVAL; } } } if (max_bonds < 1 || max_bonds > INT_MAX) { - printk(KERN_WARNING - "bonding_init(): max_bonds (%d) not in range %d-%d, " - "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)", + printk(KERN_WARNING DRV_NAME + ": Warning: max_bonds (%d) not in range %d-%d, so it " + "was reset to BOND_DEFAULT_MAX_BONDS (%d)", max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } if (miimon < 0) { - printk(KERN_WARNING - "bonding_init(): miimon module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter (%d), " "not in range 0-%d, so it was reset to %d\n", miimon, INT_MAX, BOND_LINK_MON_INTERV); miimon = BOND_LINK_MON_INTERV; } if (updelay < 0) { - printk(KERN_WARNING - "bonding_init(): updelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", updelay, INT_MAX); updelay = 0; } if (downdelay < 0) { - printk(KERN_WARNING - "bonding_init(): downdelay module parameter (%d), " + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay module parameter (%d), " "not in range 0-%d, so it was reset to 0\n", downdelay, INT_MAX); downdelay = 0; } + if ((use_carrier != 0) && (use_carrier != 1)) { + printk(KERN_WARNING DRV_NAME + ": Warning: use_carrier module parameter (%d), " + "not of valid value (0/1), so it was set to 1\n", + use_carrier); + use_carrier = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { - if (arp_interval != 0) { - printk(KERN_WARNING "bonding_init(): ARP monitoring" - "can't be used simultaneously with 802.3ad, " - "disabling ARP monitoring\n"); - arp_interval = 0; - } - - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure, " - "speed and duplex which are essential " - "for 802.3ad operation\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure, speed and duplex which are " + "essential for 802.3ad operation\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ALL) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ALL for 802.3ad\n"); - printk(KERN_ERR "Forcing Multicast mode to ALL\n"); - multicast_mode = BOND_MULTICAST_ALL; - } } /* reset values for TLB/ALB */ if ((bond_mode == BOND_MODE_TLB) || (bond_mode == BOND_MODE_ALB)) { - if (miimon == 0) { - printk(KERN_ERR - "bonding_init(): miimon must be specified, " - "otherwise bonding will not detect link failure " - "and link speed which are essential " + if (!miimon) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon must be specified, " + "otherwise bonding will not detect link " + "failure and link speed which are essential " "for TLB/ALB load balancing\n"); - printk(KERN_ERR "Forcing miimon to 100msec\n"); + printk(KERN_WARNING "Forcing miimon to 100msec\n"); miimon = 100; } - - if (multicast_mode != BOND_MULTICAST_ACTIVE) { - printk(KERN_ERR - "bonding_init(): Multicast mode must " - "be set to ACTIVE for TLB/ALB\n"); - printk(KERN_ERR "Forcing Multicast mode to ACTIVE\n"); - multicast_mode = BOND_MULTICAST_ACTIVE; - } } if (bond_mode == BOND_MODE_ALB) { - printk(KERN_INFO - "In ALB mode you might experience client disconnections" - " upon reconnection of a link if the bonding module" - " updelay parameter (%d msec) is incompatible with the" - " forwarding delay time of the switch\n", updelay); + printk(KERN_NOTICE DRV_NAME + ": In ALB mode you might experience client " + "disconnections upon reconnection of a link if the " + "bonding module updelay parameter (%d msec) is " + "incompatible with the forwarding delay time of the " + "switch\n", + updelay); } - if (miimon == 0) { - if ((updelay != 0) || (downdelay != 0)) { + if (!miimon) { + if (updelay || downdelay) { /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - printk(KERN_WARNING - "bonding_init(): miimon module parameter not " - "set and updelay (%d) or downdelay (%d) module " + printk(KERN_WARNING DRV_NAME + ": Warning: miimon module parameter not set " + "and updelay (%d) or downdelay (%d) module " "parameter is set; updelay and downdelay have " "no effect unless miimon is set\n", - updelay, downdelay); + updelay, downdelay); } } else { /* don't allow arp monitoring */ - if (arp_interval != 0) { - printk(KERN_WARNING - "bonding_init(): miimon (%d) and arp_interval " - "(%d) can't be used simultaneously, " - "disabling ARP monitoring\n", - miimon, arp_interval); + if (arp_interval) { + printk(KERN_WARNING DRV_NAME + ": Warning: miimon (%d) and arp_interval (%d) " + "can't be used simultaneously, disabling ARP " + "monitoring\n", + miimon, arp_interval); arp_interval = 0; } if ((updelay % miimon) != 0) { - /* updelay will be rounded in bond_init() when it - * is divided by miimon, we just inform user here - */ - printk(KERN_WARNING - "bonding_init(): updelay (%d) is not a multiple " + printk(KERN_WARNING DRV_NAME + ": Warning: updelay (%d) is not a multiple " "of miimon (%d), updelay rounded to %d ms\n", - updelay, miimon, (updelay / miimon) * miimon); + updelay, miimon, (updelay / miimon) * miimon); } + updelay /= miimon; + if ((downdelay % miimon) != 0) { - /* downdelay will be rounded in bond_init() when it - * is divided by miimon, we just inform user here - */ - printk(KERN_WARNING - "bonding_init(): downdelay (%d) is not a " - "multiple of miimon (%d), downdelay rounded " - "to %d ms\n", - downdelay, miimon, + printk(KERN_WARNING DRV_NAME + ": Warning: downdelay (%d) is not a multiple " + "of miimon (%d), downdelay rounded to %d ms\n", + downdelay, miimon, (downdelay / miimon) * miimon); } + + downdelay /= miimon; } if (arp_interval < 0) { - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter (%d), " - "not in range 0-%d, so it was reset to %d\n", + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + ", not in range 0-%d, so it was reset to %d\n", arp_interval, INT_MAX, BOND_LINK_ARP_INTERV); arp_interval = BOND_LINK_ARP_INTERV; } - for (arp_ip_count=0 ; - (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; - arp_ip_count++ ) { + for (arp_ip_count = 0; + (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count]; + arp_ip_count++) { /* not complete check, but should be good enough to catch mistakes */ - if (!isdigit(arp_ip_target[arp_ip_count][0])) { - printk(KERN_WARNING - "bonding_init(): bad arp_ip_target module " - "parameter (%s), ARP monitoring will not be " - "performed\n", - arp_ip_target[arp_ip_count]); - arp_interval = 0; - } else { - u32 ip = in_aton(arp_ip_target[arp_ip_count]); + if (!isdigit(arp_ip_target[arp_ip_count][0])) { + printk(KERN_WARNING DRV_NAME + ": Warning: bad arp_ip_target module parameter " + "(%s), ARP monitoring will not be performed\n", + arp_ip_target[arp_ip_count]); + arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } - } - + } - if ( (arp_interval > 0) && (arp_ip_count==0)) { + if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - printk(KERN_WARNING - "bonding_init(): arp_interval module parameter " - "(%d) specified without providing an arp_ip_target " + printk(KERN_WARNING DRV_NAME + ": Warning: arp_interval module parameter (%d) " + "specified without providing an arp_ip_target " "parameter, arp_interval was reset to 0\n", arp_interval); arp_interval = 0; } - if ((miimon == 0) && (arp_interval == 0)) { + if (miimon) { + printk(KERN_INFO DRV_NAME + ": MII link monitoring set to %d ms\n", + miimon); + } else if (arp_interval) { + int i; + + printk(KERN_INFO DRV_NAME + ": ARP monitoring set to %d ms with %d target(s):", + arp_interval, arp_ip_count); + + for (i = 0; i < arp_ip_count; i++) + printk (" %s", arp_ip_target[i]); + + printk("\n"); + + } else { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - printk(KERN_ERR - "bonding_init(): either miimon or " - "arp_interval and arp_ip_target module parameters " - "must be specified, otherwise bonding will not detect " - "link failures! see bonding.txt for details.\n"); + printk(KERN_WARNING DRV_NAME + ": Warning: either miimon or arp_interval and " + "arp_ip_target module parameters must be specified, " + "otherwise bonding will not detect link failures! see " + "bonding.txt for details.\n"); } - if ((primary != NULL) && !USES_PRIMARY(bond_mode)) { + if (primary && !USES_PRIMARY(bond_mode)) { /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - printk(KERN_WARNING - "bonding_init(): %s primary device specified but has " - "no effect in %s mode\n", - primary, bond_mode_name()); + printk(KERN_WARNING DRV_NAME + ": Warning: %s primary device specified but has no " + "effect in %s mode\n", + primary, bond_mode_name(bond_mode)); primary = NULL; } + /* fill params struct with the proper values */ + params->mode = bond_mode; + params->miimon = miimon; + params->arp_interval = arp_interval; + params->updelay = updelay; + params->downdelay = downdelay; + params->use_carrier = use_carrier; + params->lacp_fast = lacp_fast; + params->primary[0] = 0; + + if (primary) { + strncpy(params->primary, primary, IFNAMSIZ); + params->primary[IFNAMSIZ - 1] = 0; + } + + memcpy(params->arp_targets, arp_target, sizeof(arp_target)); + + return 0; +} + +static int __init bonding_init(void) +{ + struct bond_params params; + int i; + int res; + + printk(KERN_INFO "%s", version); + + res = bond_check_params(¶ms); + if (res) { + return res; + } + rtnl_lock(); #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif - err = 0; - for (no = 0; no < max_bonds; no++) { - struct net_device *dev; - - dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); - if (!dev) { - err = -ENOMEM; + for (i = 0; i < max_bonds; i++) { + struct net_device *bond_dev; + + bond_dev = alloc_netdev(sizeof(struct bonding), "", ether_setup); + if (!bond_dev) { + res = -ENOMEM; goto out_err; } - err = dev_alloc_name(dev, "bond%d"); - if (err < 0) { - free_netdev(dev); + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } @@ -4319,18 +4667,18 @@ * /proc files), but before register_netdevice(), because we * need to set function pointers. */ - err = bond_init(dev); - if (err < 0) { - free_netdev(dev); + res = bond_init(bond_dev, ¶ms); + if (res < 0) { + free_netdev(bond_dev); goto out_err; } - SET_MODULE_OWNER(dev); + SET_MODULE_OWNER(bond_dev); - err = register_netdevice(dev); - if (err < 0) { - bond_deinit(dev); - free_netdev(dev); + res = register_netdevice(bond_dev); + if (res < 0) { + bond_deinit(bond_dev); + free_netdev(bond_dev); goto out_err; } } @@ -4346,7 +4694,7 @@ rtnl_unlock(); - return err; + return res; } static void __exit bonding_exit(void) @@ -4362,6 +4710,8 @@ module_exit(bonding_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION); +MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); +MODULE_SUPPORTED_DEVICE("most ethernet devices"); /* * Local variables: @@ -4370,3 +4720,4 @@ * tab-width: 8 * End: */ + diff -urN linux-2.4.25/drivers/net/bonding/bonding.h linux-2.4.26/drivers/net/bonding/bonding.h --- linux-2.4.25/drivers/net/bonding/bonding.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/bonding/bonding.h 2004-04-14 06:05:30.000000000 -0700 @@ -9,7 +9,7 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * * 2003/03/18 - Amir Noam , * Tsippy Mendelson and @@ -22,160 +22,231 @@ * * 2003/05/01 - Shmulik Hen * - Added support for Transmit load balancing mode. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ - + #ifndef _LINUX_BONDING_H #define _LINUX_BONDING_H #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#ifdef BONDING_DEBUG +#define DRV_VERSION "2.6.0" +#define DRV_RELDATE "January 14, 2004" +#define DRV_NAME "bonding" +#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" -// use this like so: BOND_PRINT_DBG(("foo = %d, bar = %d", foo, bar)); -#define BOND_PRINT_DBG(X) \ -do { \ - printk(KERN_DEBUG "%s (%d)", __FUNCTION__, __LINE__); \ - printk X; \ - printk("\n"); \ -} while(0) +#define BOND_MAX_ARP_TARGETS 16 +#ifdef BONDING_DEBUG +#define dprintk(fmt, args...) \ + printk(KERN_DEBUG \ + DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args ) #else -#define BOND_PRINT_DBG(X) +#define dprintk(fmt, args...) #endif /* BONDING_DEBUG */ -#define IS_UP(dev) ((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \ - (netif_running(dev) && netif_carrier_ok(dev))) +#define IS_UP(dev) \ + ((((dev)->flags & IFF_UP) == IFF_UP) && \ + netif_running(dev) && \ + netif_carrier_ok(dev)) + +/* + * Checks whether bond is ready for transmit. + * + * Caller must hold bond->lock + */ +#define BOND_IS_OK(bond) \ + (((bond)->dev->flags & IFF_UP) && \ + netif_running((bond)->dev) && \ + ((bond)->slave_cnt > 0)) -/* Checks whether the dev is ready for transmit. We do not check netif_running - * since a device can be stopped by the driver for short periods of time for - * maintainance. dev_queue_xmit() handles this by queing the packet until the - * the dev is running again. Keeping packets ordering requires sticking the - * same dev as much as possible - */ -#define SLAVE_IS_OK(slave) \ - ((((slave)->dev->flags & (IFF_UP)) == (IFF_UP)) && \ - netif_carrier_ok((slave)->dev) && \ +/* + * Checks whether slave is ready for transmit. + */ +#define SLAVE_IS_OK(slave) \ + (((slave)->dev->flags & IFF_UP) && \ + netif_running((slave)->dev) && \ ((slave)->link == BOND_LINK_UP) && \ ((slave)->state == BOND_STATE_ACTIVE)) -typedef struct slave { +#define USES_PRIMARY(mode) \ + (((mode) == BOND_MODE_ACTIVEBACKUP) || \ + ((mode) == BOND_MODE_TLB) || \ + ((mode) == BOND_MODE_ALB)) + +/* + * Less bad way to call ioctl from within the kernel; this needs to be + * done some other way to get the call out of interrupt context. + * Needs "ioctl" variable to be supplied by calling context. + */ +#define IOCTL(dev, arg, cmd) ({ \ + int res = 0; \ + mm_segment_t fs = get_fs(); \ + set_fs(get_ds()); \ + res = ioctl(dev, arg, cmd); \ + set_fs(fs); \ + res; }) + +/** + * bond_for_each_slave_from - iterate the slaves list from a starting point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * @start: starting point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from(bond, pos, cnt, start) \ + for (cnt = 0, pos = start; \ + cnt < (bond)->slave_cnt; \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave_from_to - iterate the slaves list from start point to stop point + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for number max of moves + * @start: start point. + * @stop: stop point. + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave_from_to(bond, pos, cnt, start, stop) \ + for (cnt = 0, pos = start; \ + ((cnt < (bond)->slave_cnt) && (pos != (stop)->next)); \ + cnt++, pos = (pos)->next) + +/** + * bond_for_each_slave - iterate the slaves list from head + * @bond: the bond holding this list. + * @pos: current slave. + * @cnt: counter for max number of moves + * + * Caller must hold bond->lock + */ +#define bond_for_each_slave(bond, pos, cnt) \ + bond_for_each_slave_from(bond, pos, cnt, (bond)->first_slave) + + +struct bond_params { + int mode; + int miimon; + int arp_interval; + int use_carrier; + int updelay; + int downdelay; + int lacp_fast; + char primary[IFNAMSIZ]; + u32 arp_targets[BOND_MAX_ARP_TARGETS]; +}; + +struct vlan_entry { + struct list_head vlan_list; + unsigned short vlan_id; +}; + +struct slave { + struct net_device *dev; /* first - usefull for panic debug */ struct slave *next; struct slave *prev; - struct net_device *dev; - short delay; - unsigned long jiffies; - char link; /* one of BOND_LINK_XXXX */ - char state; /* one of BOND_STATE_XXXX */ - unsigned short original_flags; - u32 link_failure_count; + s16 delay; + u32 jiffies; + s8 link; /* one of BOND_LINK_XXXX */ + s8 state; /* one of BOND_STATE_XXXX */ + u32 original_flags; + u32 link_failure_count; u16 speed; u8 duplex; u8 perm_hwaddr[ETH_ALEN]; struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */ struct tlb_slave_info tlb_info; -} slave_t; +}; /* * Here are the locking policies for the two bonding locks: * * 1) Get bond->lock when reading/writing slave list. - * 2) Get bond->ptrlock when reading/writing bond->current_slave. + * 2) Get bond->curr_slave_lock when reading/writing bond->curr_active_slave. * (It is unnecessary when the write-lock is put with bond->lock.) - * 3) When we lock with bond->ptrlock, we must lock with bond->lock + * 3) When we lock with bond->curr_slave_lock, we must lock with bond->lock * beforehand. */ -typedef struct bonding { - slave_t *next; - slave_t *prev; - slave_t *current_slave; - slave_t *primary_slave; - slave_t *current_arp_slave; - __s32 slave_cnt; +struct bonding { + struct net_device *dev; /* first - usefull for panic debug */ + struct slave *first_slave; + struct slave *curr_active_slave; + struct slave *current_arp_slave; + struct slave *primary_slave; + s32 slave_cnt; /* never change this value outside the attach/detach wrappers */ rwlock_t lock; - rwlock_t ptrlock; - struct timer_list mii_timer; - struct timer_list arp_timer; - struct net_device_stats stats; + rwlock_t curr_slave_lock; + struct timer_list mii_timer; + struct timer_list arp_timer; + s8 kill_timers; + struct net_device_stats stats; #ifdef CONFIG_PROC_FS - struct proc_dir_entry *bond_proc_file; - char procdir_name[IFNAMSIZ]; + struct proc_dir_entry *proc_entry; + char proc_file_name[IFNAMSIZ]; #endif /* CONFIG_PROC_FS */ - struct list_head bond_list; - struct net_device *device; - struct dev_mc_list *mc_list; - unsigned short flags; - struct ad_bond_info ad_info; - struct alb_bond_info alb_info; -} bonding_t; - -/* Forward declarations */ -void bond_set_slave_active_flags(slave_t *slave); -void bond_set_slave_inactive_flags(slave_t *slave); - -/** - * These functions can be used for iterating the slave list - * (which is circular) - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_first_slave(struct bonding *bond) -{ - /* if there are no slaves return NULL */ - if (bond->next == (slave_t *)bond) { - return NULL; - } - return bond->next; -} - -/** - * Caller must hold bond lock for read - */ -extern inline struct slave* -bond_get_next_slave(struct bonding *bond, struct slave *slave) -{ - /* If we have reached the last slave return NULL */ - if (slave->next == bond->next) { - return NULL; - } - return slave->next; -} + struct list_head bond_list; + struct dev_mc_list *mc_list; + u16 flags; + struct ad_bond_info ad_info; + struct alb_bond_info alb_info; + struct bond_params params; + struct list_head vlan_list; + struct vlan_group *vlgrp; +}; /** * Returns NULL if the net_device does not belong to any of the bond's slaves * * Caller must hold bond lock for read */ -extern inline struct slave* -bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) +extern inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct net_device *slave_dev) { - struct slave *our_slave = bond->next; + struct slave *slave = NULL; + int i; - /* check if the list of slaves is empty */ - if (our_slave == (slave_t *)bond) { - return NULL; - } - - for (; our_slave; our_slave = bond_get_next_slave(bond, our_slave)) { - if (our_slave->dev == slave_dev) { + bond_for_each_slave(bond, slave, i) { + if (slave->dev == slave_dev) { break; } } - return our_slave; + + return slave; } -extern inline struct bonding* -bond_get_bond_by_slave(struct slave *slave) +extern inline struct bonding *bond_get_bond_by_slave(struct slave *slave) { if (!slave || !slave->dev->master) { return NULL; } - return (struct bonding *)(slave->dev->master->priv); + return (struct bonding *)slave->dev->master->priv; } +extern inline void bond_set_slave_inactive_flags(struct slave *slave) +{ + slave->state = BOND_STATE_BACKUP; + slave->dev->flags |= IFF_NOARP; +} + +extern inline void bond_set_slave_active_flags(struct slave *slave) +{ + slave->state = BOND_STATE_ACTIVE; + slave->dev->flags &= ~IFF_NOARP; +} + +struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); +int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); + #endif /* _LINUX_BONDING_H */ diff -urN linux-2.4.25/drivers/net/e1000/e1000.h linux-2.4.26/drivers/net/e1000/e1000.h --- linux-2.4.25/drivers/net/e1000/e1000.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -92,6 +92,16 @@ #define E1000_MAX_INTR 10 +/* How many descriptors for TX and RX ? */ +#define E1000_DEFAULT_TXD 256 +#define E1000_MAX_TXD 256 +#define E1000_MIN_TXD 80 +#define E1000_MAX_82544_TXD 4096 +#define E1000_DEFAULT_RXD 256 +#define E1000_MAX_RXD 256 +#define E1000_MIN_RXD 80 +#define E1000_MAX_82544_RXD 4096 + /* Supported Rx Buffer Sizes */ #define E1000_RXBUFFER_2048 2048 #define E1000_RXBUFFER_4096 4096 @@ -192,10 +202,14 @@ /* TX */ struct e1000_desc_ring tx_ring; + spinlock_t tx_lock; uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; uint32_t gotcl; + uint64_t gotcl_old; + uint64_t tpt_old; + uint64_t colc_old; uint32_t tx_fifo_head; uint32_t tx_head_addr; uint32_t tx_fifo_size; @@ -210,6 +224,7 @@ uint32_t rx_abs_int_delay; boolean_t rx_csum; uint32_t gorcl; + uint64_t gorcl_old; /* Interrupt Throttle Rate */ uint32_t itr; diff -urN linux-2.4.25/drivers/net/e1000/e1000_ethtool.c linux-2.4.26/drivers/net/e1000/e1000_ethtool.c --- linux-2.4.25/drivers/net/e1000/e1000_ethtool.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_ethtool.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -39,6 +39,11 @@ extern void e1000_down(struct e1000_adapter *adapter); extern void e1000_reset(struct e1000_adapter *adapter); extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +extern int e1000_setup_rx_resources(struct e1000_adapter *adapter); +extern int e1000_setup_tx_resources(struct e1000_adapter *adapter); +extern void e1000_free_rx_resources(struct e1000_adapter *adapter); +extern void e1000_free_tx_resources(struct e1000_adapter *adapter); +extern void e1000_update_stats(struct e1000_adapter *adapter); struct e1000_stats { char stat_string[ETH_GSTRING_LEN]; @@ -579,8 +584,8 @@ *data = 0; /* Hook up test interrupt handler just for this test */ - if(request_irq - (netdev->irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)) { + if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ, + netdev->name, netdev)) { *data = 1; return -1; } @@ -664,7 +669,7 @@ msec_delay(10); /* Unhook test interrupt handler */ - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); return *data; } @@ -770,9 +775,9 @@ PCI_DMA_TODEVICE); tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(skb->len); - tx_desc->lower.data |= E1000_TXD_CMD_EOP; - tx_desc->lower.data |= E1000_TXD_CMD_IFCS; - tx_desc->lower.data |= E1000_TXD_CMD_RPS; + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RPS); tx_desc->upper.data = 0; } @@ -1522,6 +1527,7 @@ } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} }; int i; + e1000_update_stats(adapter); for(i = 0; i < E1000_STATS_LEN; i++) stats.data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? diff -urN linux-2.4.25/drivers/net/e1000/e1000_hw.c linux-2.4.26/drivers/net/e1000/e1000_hw.c --- linux-2.4.25/drivers/net/e1000/e1000_hw.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_hw.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -96,8 +96,14 @@ hw->phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: - hw->phy_type = e1000_phy_igp; - break; + if(hw->mac_type == e1000_82541 || + hw->mac_type == e1000_82541_rev_2 || + hw->mac_type == e1000_82547 || + hw->mac_type == e1000_82547_rev_2) { + hw->phy_type = e1000_phy_igp; + break; + } + /* Fall Through */ default: /* Should never have loaded on this device */ hw->phy_type = e1000_phy_undefined; @@ -148,7 +154,6 @@ e1000_write_phy_reg(hw, 0x0000, 0x3300); - if(hw->mac_type == e1000_82547) { uint16_t fused, fine, coarse; @@ -1485,8 +1490,8 @@ if(mii_status_reg & MII_SR_LINK_STATUS) break; msec_delay(100); } - if(i == 0) { /* We didn't get link */ - /* Reset the DSP and wait again for link. */ + if((i == 0) && (hw->phy_type == e1000_phy_m88)) { + /* We didn't get link. Reset the DSP and wait again for link. */ if((ret_val = e1000_phy_reset_dsp(hw))) { DEBUGOUT("Error Resetting PHY DSP\n"); return ret_val; @@ -1533,6 +1538,25 @@ phy_data))) return ret_val; + /* Polarity reversal workaround for forced 10F/10H links. */ + if(hw->mac_type <= e1000_82544 && + (hw->forced_speed_duplex == e1000_10_full || + hw->forced_speed_duplex == e1000_10_half)) { + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F0F))) + return ret_val; + /* IEEE requirement is 150ms */ + msec_delay(200); + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, + 0x0019))) + return ret_val; + if((ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, + 0x8F00))) + return ret_val; + } } return E1000_SUCCESS; } @@ -1916,7 +1940,6 @@ uint32_t signal = 0; int32_t ret_val; uint16_t phy_data; - uint16_t lp_capability; DEBUGFUNC("e1000_check_for_link"); @@ -1996,24 +2019,17 @@ /* At this point we know that we are on copper and we have * auto-negotiated link. These are conditions for checking the link - * parter capability register. We use the link partner capability to - * determine if TBI Compatibility needs to be turned on or off. If - * the link partner advertises any speed in addition to Gigabit, then - * we assume that they are GMII-based, and TBI compatibility is not - * needed. If no other speeds are advertised, we assume the link - * partner is TBI-based, and we turn on TBI Compatibility. - */ - if(hw->tbi_compatibility_en) { - if((ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, - &lp_capability))) - return ret_val; - if(lp_capability & (NWAY_LPAR_10T_HD_CAPS | - NWAY_LPAR_10T_FD_CAPS | - NWAY_LPAR_100TX_HD_CAPS | - NWAY_LPAR_100TX_FD_CAPS | - NWAY_LPAR_100T4_CAPS)) { - /* If our link partner advertises anything in addition to - * gigabit, we do not need to enable TBI compatibility. + * partner capability register. We use the link speed to determine if + * TBI compatibility needs to be turned on or off. If the link is not + * at gigabit speed, then TBI compatibility is not needed. If we are + * at gigabit speed, we turn on TBI compatibility. + */ + if(hw->tbi_compatibility_en) { + uint16_t speed, duplex; + e1000_get_speed_and_duplex(hw, &speed, &duplex); + if(speed != SPEED_1000) { + /* If link speed is not set to gigabit speed, we do not need + * to enable TBI compatibility. */ if(hw->tbi_compatibility_on) { /* If we previously were in the mode, turn it off. */ @@ -2081,6 +2097,29 @@ DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n"); E1000_WRITE_REG(hw, TXCW, hw->txcw); E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU)); + + hw->serdes_link_down = FALSE; + } + /* If we force link for non-auto-negotiation switch, check link status + * based on MAC synchronization for internal serdes media type. + */ + else if((hw->media_type == e1000_media_type_internal_serdes) && + !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + /* SYNCH bit and IV bit are sticky. */ + udelay(10); + if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) { + if(!(rxcw & E1000_RXCW_IV)) { + hw->serdes_link_down = FALSE; + DEBUGOUT("SERDES: Link is up.\n"); + } + } else { + hw->serdes_link_down = TRUE; + DEBUGOUT("SERDES: Link is down.\n"); + } + } + if((hw->media_type == e1000_media_type_internal_serdes) && + (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) { + hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS)); } return E1000_SUCCESS; } @@ -3742,22 +3781,13 @@ e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; - uint32_t addr_low; - uint32_t addr_high; DEBUGFUNC("e1000_init_rx_addrs"); /* Setup the receive address. */ DEBUGOUT("Programming MAC Address into RAR[0]\n"); - addr_low = (hw->mac_addr[0] | - (hw->mac_addr[1] << 8) | - (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24)); - - addr_high = (hw->mac_addr[4] | - (hw->mac_addr[5] << 8) | E1000_RAH_AV); - E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low); - E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high); + e1000_rar_set(hw, hw->mac_addr, 0); /* Zero out the other 15 receive addresses. */ DEBUGOUT("Clearing RAR[1-15]\n"); @@ -3774,6 +3804,7 @@ * mc_addr_list - the list of new multicast addresses * mc_addr_count - number of addresses * pad - number of bytes between addresses in the list + * rar_used_count - offset where to start adding mc addresses into the RAR's * * The given list replaces any existing list. Clears the last 15 receive * address registers and the multicast table. Uses receive address registers @@ -3784,11 +3815,11 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t *mc_addr_list, uint32_t mc_addr_count, - uint32_t pad) + uint32_t pad, + uint32_t rar_used_count) { uint32_t hash_value; uint32_t i; - uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */ DEBUGFUNC("e1000_mc_addr_list_update"); @@ -4522,8 +4553,8 @@ e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); @@ -4542,8 +4573,8 @@ uint32_t offset, uint32_t value) { - uint32_t io_addr = hw->io_base; - uint32_t io_data = hw->io_base + 4; + unsigned long io_addr = hw->io_base; + unsigned long io_data = hw->io_base + 4; e1000_io_write(hw, io_addr, offset); e1000_io_write(hw, io_data, value); diff -urN linux-2.4.25/drivers/net/e1000/e1000_hw.h linux-2.4.26/drivers/net/e1000/e1000_hw.h --- linux-2.4.25/drivers/net/e1000/e1000_hw.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_hw.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -291,7 +291,7 @@ /* Filters (multicast, vlan, receive) */ void e1000_init_rx_addrs(struct e1000_hw *hw); -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad); +void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); @@ -317,9 +317,9 @@ void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ -uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port); +uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); -void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value); +void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); @@ -978,7 +978,7 @@ e1000_ms_type master_slave; e1000_ms_type original_master_slave; e1000_ffe_config ffe_config_state; - uint32_t io_base; + unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; uint32_t phy_addr; @@ -1021,6 +1021,7 @@ boolean_t speed_downgraded; e1000_dsp_config dsp_config_state; boolean_t get_link_status; + boolean_t serdes_link_down; boolean_t tbi_compatibility_en; boolean_t tbi_compatibility_on; boolean_t phy_reset_disable; @@ -1310,6 +1311,7 @@ #define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ diff -urN linux-2.4.25/drivers/net/e1000/e1000_main.c linux-2.4.26/drivers/net/e1000/e1000_main.c --- linux-2.4.25/drivers/net/e1000/e1000_main.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_main.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -30,10 +30,24 @@ /* Change Log * - * 5.2.20 9/30/03 + * 5.2.30.1 1/29/03 + * o Set VLAN filtering to IEEE 802.1Q after reset so we don't break + * SoL connections that use VLANs. + * o Allow 1000/Full setting for AutoNeg param for Fiber connections + * Jon D Mason [jonmason@us.ibm.com]. + * o Race between Tx queue and Tx clean fixed with a spin lock. + * o Added netpoll support. + * o Fixed endianess bug causing ethtool loopback diags to fail on ppc. + * o Use pdev->irq rather than netdev->irq in preparation for MSI support. + * o Report driver message on user override of InterruptThrottleRate + * module parameter. + * o Change I/O address storage from uint32_t to unsigned long. + * + * 5.2.22 10/15/03 * o Bug fix: SERDES devices might be connected to a back-plane * switch that doesn't support auto-neg, so add the capability - * to force 1000/Full. + * to force 1000/Full. Also, since forcing 1000/Full, sample + * RxSynchronize bit to detect link state. * o Bug fix: Flow control settings for hi/lo watermark didn't * consider changes in the Rx FIFO size, which could occur with * Jumbo Frames or with the reduced FIFO in 82547. @@ -42,30 +56,19 @@ * o Bug fix: hang under heavy Tx stress when running out of Tx * descriptors; wasn't clearing context descriptor when backing * out of send because of no-resource condition. + * o Bug fix: check netif_running in dev->poll so we don't have to + * hang in dev->close until all polls are finished. [Robert + * Ollson (robert.olsson@data.slu.se)]. + * o Revert TxDescriptor ring size back to 256 since change to 1024 + * wasn't accepted into the kernel. * * 5.2.16 8/8/03 - * o Added support for new controllers: 82545GM, 82546GB, 82541/7_B1 - * o Bug fix: reset h/w before first EEPROM read because we don't know - * who may have been messing with the device before we got there. - * [Dave Johnson (ddj -a-t- cascv.brown.edu)] - * o Bug fix: read the correct work from EEPROM to detect programmed - * WoL settings. - * o Bug fix: TSO would hang if space left in FIFO was being miscalculated - * when mss dropped without a correspoding drop in the DMA buffer size. - * o ASF for Fiber nics isn't supported. - * o Bug fix: Workaround added for potential hang with 82544 running in - * PCI-X if send buffer terminates within an evenly-aligned dword. - * o Feature: Add support for ethtool flow control setting. - * o Feature: Add support for ethtool TSO setting. - * o Feature: Increase default Tx Descriptor count to 1024 for >= 82544. - * - * 5.1.13 5/28/03 */ char e1000_driver_name[] = "e1000"; char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; -char e1000_driver_version[] = "5.2.20-k1"; -char e1000_copyright[] = "Copyright (c) 1999-2003 Intel Corporation."; +char e1000_driver_version[] = "5.2.30.1-k1"; +char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * @@ -89,7 +92,6 @@ {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x1014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -113,12 +115,17 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -/* Local Function Prototypes */ - int e1000_up(struct e1000_adapter *adapter); void e1000_down(struct e1000_adapter *adapter); void e1000_reset(struct e1000_adapter *adapter); int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); +int e1000_setup_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_rx_resources(struct e1000_adapter *adapter); +void e1000_free_tx_resources(struct e1000_adapter *adapter); +void e1000_free_rx_resources(struct e1000_adapter *adapter); +void e1000_update_stats(struct e1000_adapter *adapter); + +/* Local Function Prototypes */ static int e1000_init_module(void); static void e1000_exit_module(void); @@ -127,15 +134,11 @@ static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); -static int e1000_setup_tx_resources(struct e1000_adapter *adapter); -static int e1000_setup_rx_resources(struct e1000_adapter *adapter); static void e1000_configure_tx(struct e1000_adapter *adapter); static void e1000_configure_rx(struct e1000_adapter *adapter); static void e1000_setup_rctl(struct e1000_adapter *adapter); static void e1000_clean_tx_ring(struct e1000_adapter *adapter); static void e1000_clean_rx_ring(struct e1000_adapter *adapter); -static void e1000_free_tx_resources(struct e1000_adapter *adapter); -static void e1000_free_rx_resources(struct e1000_adapter *adapter); static void e1000_set_multi(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); @@ -144,7 +147,6 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev); static int e1000_change_mtu(struct net_device *netdev, int new_mtu); static int e1000_set_mac(struct net_device *netdev, void *p); -static void e1000_update_stats(struct e1000_adapter *adapter); static inline void e1000_irq_disable(struct e1000_adapter *adapter); static inline void e1000_irq_enable(struct e1000_adapter *adapter); static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs); @@ -182,6 +184,11 @@ static int e1000_resume(struct pci_dev *pdev); #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* for netdump / net console */ +static void e1000_netpoll (struct net_device *dev); +#endif + struct notifier_block e1000_notifier_reboot = { .notifier_call = e1000_notify_reboot, .next = NULL, @@ -268,7 +275,7 @@ e1000_configure_rx(adapter); e1000_alloc_rx_buffers(adapter); - if((err = request_irq(netdev->irq, &e1000_intr, + if((err = request_irq(adapter->pdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, netdev))) return err; @@ -285,7 +292,7 @@ struct net_device *netdev = adapter->netdev; e1000_irq_disable(adapter); - free_irq(netdev->irq, netdev); + free_irq(adapter->pdev->irq, netdev); del_timer_sync(&adapter->tx_fifo_stall_timer); del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_info_timer); @@ -336,6 +343,10 @@ if(adapter->hw.mac_type >= e1000_82544) E1000_WRITE_REG(&adapter->hw, WUC, 0); e1000_init_hw(&adapter->hw); + + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); + e1000_reset_adaptive(&adapter->hw); e1000_phy_get_info(&adapter->hw, &adapter->phy_info); } @@ -433,8 +444,10 @@ netdev->vlan_rx_register = e1000_vlan_rx_register; netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = e1000_netpoll; +#endif - netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len; netdev->base_addr = adapter->hw.io_base; @@ -668,6 +681,7 @@ atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->tx_lock); return 0; } @@ -748,7 +762,7 @@ * Return 0 on success, negative on failure **/ -static int +int e1000_setup_tx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *txdr = &adapter->tx_ring; @@ -865,7 +879,7 @@ * Returns 0 on success, negative on failure **/ -static int +int e1000_setup_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rxdr = &adapter->rx_ring; @@ -1004,7 +1018,7 @@ * Free all transmit software resources **/ -static void +void e1000_free_tx_resources(struct e1000_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; @@ -1072,7 +1086,7 @@ * Free all receive software resources **/ -static void +void e1000_free_rx_resources(struct e1000_adapter *adapter) { struct e1000_desc_ring *rx_ring = &adapter->rx_ring; @@ -1280,41 +1294,6 @@ e1000_leave_82542_rst(adapter); } -static void -e1000_tx_flush(struct e1000_adapter *adapter) -{ - uint32_t ctrl, tctl, txcw, icr; - - e1000_irq_disable(adapter); - - if(adapter->hw.mac_type < e1000_82543) { - /* Transmit Unit Reset */ - tctl = E1000_READ_REG(&adapter->hw, TCTL); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST); - E1000_WRITE_REG(&adapter->hw, TCTL, tctl); - e1000_clean_tx_ring(adapter); - e1000_configure_tx(adapter); - } else { - txcw = E1000_READ_REG(&adapter->hw, TXCW); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE); - - ctrl = E1000_READ_REG(&adapter->hw, CTRL); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU | - E1000_CTRL_ILOS); - - mdelay(10); - - e1000_clean_tx_irq(adapter); - E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); - E1000_WRITE_REG(&adapter->hw, TXCW, txcw); - - /* clear the link status change interrupts this caused */ - icr = E1000_READ_REG(&adapter->hw, ICR); - } - - e1000_irq_enable(adapter); -} - /* need to wait a few seconds after link up to get diagnostic information from the phy */ static void @@ -1378,10 +1357,17 @@ struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; unsigned int i; + uint32_t link; e1000_check_for_link(&adapter->hw); - if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) { + if((adapter->hw.media_type == e1000_media_type_internal_serdes) && + !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) + link = !adapter->hw.serdes_link_down; + else + link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; + + if(link) { if(!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, @@ -1414,14 +1400,26 @@ } e1000_update_stats(adapter); + + adapter->hw.tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; + adapter->tpt_old = adapter->stats.tpt; + adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; + adapter->colc_old = adapter->stats.colc; + + adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; + adapter->gorcl_old = adapter->stats.gorcl; + adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; + adapter->gotcl_old = adapter->stats.gotcl; + e1000_update_adaptive(&adapter->hw); if(!netif_carrier_ok(netdev)) { if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { - unsigned long flags; - spin_lock_irqsave(&netdev->xmit_lock, flags); - e1000_tx_flush(adapter); - spin_unlock_irqrestore(&netdev->xmit_lock, flags); + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + schedule_task(&adapter->tx_timeout_task); } } @@ -1685,7 +1683,7 @@ i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - + return count; } @@ -1782,6 +1780,7 @@ struct e1000_adapter *adapter = netdev->priv; unsigned int first; unsigned int tx_flags = 0; + unsigned long flags; int count; if(skb->len <= 0) { @@ -1789,10 +1788,13 @@ return 0; } + spin_lock_irqsave(&adapter->tx_lock, flags); + if(adapter->hw.mac_type == e1000_82547) { if(e1000_82547_fifo_workaround(adapter, skb)) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return 1; } } @@ -1813,11 +1815,14 @@ e1000_tx_queue(adapter, count, tx_flags); else { netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return 1; } netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->tx_lock, flags); + return 0; } @@ -1859,6 +1864,7 @@ { struct e1000_adapter *adapter = netdev->priv; + e1000_update_stats(adapter); return &adapter->net_stats; } @@ -1917,7 +1923,7 @@ * @adapter: board private structure **/ -static void +void e1000_update_stats(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; @@ -1935,8 +1941,7 @@ adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS); adapter->stats.gprc += E1000_READ_REG(hw, GPRC); - adapter->gorcl = E1000_READ_REG(hw, GORCL); - adapter->stats.gorcl += adapter->gorcl; + adapter->stats.gorcl += E1000_READ_REG(hw, GORCL); adapter->stats.gorch += E1000_READ_REG(hw, GORCH); adapter->stats.bprc += E1000_READ_REG(hw, BPRC); adapter->stats.mprc += E1000_READ_REG(hw, MPRC); @@ -1948,8 +1953,6 @@ adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); - spin_unlock_irqrestore(&adapter->stats_lock, flags); - /* the rest of the counters are only modified here */ adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); @@ -1967,8 +1970,7 @@ adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC); adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC); adapter->stats.gptc += E1000_READ_REG(hw, GPTC); - adapter->gotcl = E1000_READ_REG(hw, GOTCL); - adapter->stats.gotcl += adapter->gotcl; + adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL); adapter->stats.gotch += E1000_READ_REG(hw, GOTCH); adapter->stats.rnbc += E1000_READ_REG(hw, RNBC); adapter->stats.ruc += E1000_READ_REG(hw, RUC); @@ -2050,6 +2052,8 @@ !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) adapter->phy_stats.receive_errors += phy_tmp; } + + spin_unlock_irqrestore(&adapter->stats_lock, flags); } /** @@ -2092,6 +2096,7 @@ { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; + struct e1000_hw *hw = &adapter->hw; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); #ifndef CONFIG_E1000_NAPI unsigned int i; @@ -2101,7 +2106,7 @@ return IRQ_NONE; /* Not our interrupt */ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { - adapter->hw.get_link_status = 1; + hw->get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } @@ -2113,14 +2118,30 @@ */ atomic_inc(&adapter->irq_sem); - E1000_WRITE_REG(&adapter->hw, IMC, ~0); + E1000_WRITE_REG(hw, IMC, ~0); __netif_rx_schedule(netdev); } #else + /* Writing IMC and IMS is needed for 82547. + Due to Hub Link bus being occupied, an interrupt + de-assertion message is not able to be sent. + When an interrupt assertion message is generated later, + two messages are re-ordered and sent out. + That causes APIC to think 82547 is in de-assertion + state, while 82547 is in assertion state, resulting + in dead lock. Writing IMC forces 82547 into + de-assertion state. + */ + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_disable(adapter); + for(i = 0; i < E1000_MAX_INTR; i++) if(!e1000_clean_rx_irq(adapter) & !e1000_clean_tx_irq(adapter)) break; + + if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) + e1000_irq_enable(adapter); #endif return IRQ_HANDLED; @@ -2145,7 +2166,7 @@ *budget -= work_done; netdev->quota -= work_done; - if(work_done < work_to_do) { + if(work_done < work_to_do || !netif_running(netdev)) { netif_rx_complete(netdev); e1000_irq_enable(adapter); } @@ -2170,6 +2191,8 @@ unsigned int i, eop; boolean_t cleaned = FALSE; + spin_lock(&adapter->tx_lock); + i = tx_ring->next_to_clean; eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -2214,6 +2237,8 @@ if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) netif_wake_queue(netdev); + spin_unlock(&adapter->tx_lock); + return cleaned; } @@ -2641,13 +2666,13 @@ } uint32_t -e1000_io_read(struct e1000_hw *hw, uint32_t port) +e1000_io_read(struct e1000_hw *hw, unsigned long port) { return inl(port); } void -e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value) +e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value) { outl(value, port); } @@ -2664,8 +2689,6 @@ if(grp) { /* enable VLAN tag insert/strip */ - E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE); - ctrl = E1000_READ_REG(&adapter->hw, CTRL); ctrl |= E1000_CTRL_VME; E1000_WRITE_REG(&adapter->hw, CTRL, ctrl); @@ -2899,4 +2922,20 @@ } #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void e1000_netpoll (struct net_device *dev) +{ + struct e1000_adapter *adapter = dev->priv; + disable_irq(adapter->pdev->irq); + e1000_intr (adapter->pdev->irq, dev, NULL); + enable_irq(adapter->pdev->irq); +} +#endif + /* e1000_main.c */ diff -urN linux-2.4.25/drivers/net/e1000/e1000_osdep.h linux-2.4.26/drivers/net/e1000/e1000_osdep.h --- linux-2.4.25/drivers/net/e1000/e1000_osdep.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_osdep.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 diff -urN linux-2.4.25/drivers/net/e1000/e1000_param.c linux-2.4.26/drivers/net/e1000/e1000_param.c --- linux-2.4.25/drivers/net/e1000/e1000_param.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/e1000/e1000_param.c 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /******************************************************************************* - Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. + Copyright(c) 1999 - 2004 Intel 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 @@ -63,7 +63,7 @@ /* Transmit Descriptor Count * * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers - * Valid Range: 80-4096 for 82544 + * Valid Range: 80-4096 for 82544 and newer * * Default Value: 256 */ @@ -73,7 +73,7 @@ /* Receive Descriptor Count * * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers - * Valid Range: 80-4096 for 82544 + * Valid Range: 80-4096 for 82544 and newer * * Default Value: 256 */ @@ -196,16 +196,6 @@ #define AUTONEG_ADV_MASK 0x2F #define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL -#define DEFAULT_TXD 256 -#define MAX_TXD 256 -#define MIN_TXD 80 -#define MAX_82544_TXD 4096 - -#define DEFAULT_RXD 256 -#define MAX_RXD 256 -#define MIN_RXD 80 -#define MAX_82544_RXD 4096 - #define DEFAULT_RDTR 0 #define MAX_RXDELAY 0xFFFF #define MIN_RXDELAY 0 @@ -299,7 +289,7 @@ * e1000_check_options - Range Checking for Command Line Parameters * @adapter: board private structure * - * This routine checks all command line paramters for valid user + * This routine checks all command line parameters for valid user * input. If an invalid value is given, or if no user specified * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. @@ -320,14 +310,15 @@ struct e1000_option opt = { .type = range_option, .name = "Transmit Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_TXD), - .def = DEFAULT_TXD, - .arg = { .r = { .min = MIN_TXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_TXD), + .def = E1000_DEFAULT_TXD, + .arg = { .r = { .min = E1000_MIN_TXD }} }; struct e1000_desc_ring *tx_ring = &adapter->tx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; opt.arg.r.max = mac_type < e1000_82544 ? - MAX_TXD : MAX_82544_TXD; + E1000_MAX_TXD : E1000_MAX_82544_TXD; tx_ring->count = TxDescriptors[bd]; e1000_validate_option(&tx_ring->count, &opt); @@ -337,13 +328,15 @@ struct e1000_option opt = { .type = range_option, .name = "Receive Descriptors", - .err = "using default of " __MODULE_STRING(DEFAULT_RXD), - .def = DEFAULT_RXD, - .arg = { .r = { .min = MIN_RXD }} + .err = "using default of " + __MODULE_STRING(E1000_DEFAULT_RXD), + .def = E1000_DEFAULT_RXD, + .arg = { .r = { .min = E1000_MIN_RXD }} }; struct e1000_desc_ring *rx_ring = &adapter->rx_ring; e1000_mac_type mac_type = adapter->hw.mac_type; - opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD; + opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD : + E1000_MAX_82544_RXD; rx_ring->count = RxDescriptors[bd]; e1000_validate_option(&rx_ring->count, &opt); @@ -446,13 +439,19 @@ }; adapter->itr = InterruptThrottleRate[bd]; - if(adapter->itr == 0) { - printk(KERN_INFO "%s turned off\n", opt.name); - } else if(adapter->itr == 1 || adapter->itr == -1) { - /* Dynamic mode */ + switch(adapter->itr) { + case -1: adapter->itr = 1; - } else { + break; + case 0: + printk(KERN_INFO "%s turned off\n", opt.name); + break; + case 1: + printk(KERN_INFO "%s set to dynamic mode\n", opt.name); + break; + default: e1000_validate_option(&adapter->itr, &opt); + break; } } @@ -490,9 +489,9 @@ printk(KERN_INFO "Duplex not valid for fiber adapters, " "parameter ignored\n"); } - if((AutoNeg[bd] != OPTION_UNSET)) { - printk(KERN_INFO "AutoNeg not valid for fiber adapters, " - "parameter ignored\n"); + if((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) { + printk(KERN_INFO "AutoNeg other than Full/1000 is " + "not valid for fiber adapters, parameter ignored\n"); } } diff -urN linux-2.4.25/drivers/net/forcedeth.c linux-2.4.26/drivers/net/forcedeth.c --- linux-2.4.25/drivers/net/forcedeth.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/net/forcedeth.c 2004-04-14 06:05:30.000000000 -0700 @@ -0,0 +1,1623 @@ +/* + * forcedeth: Ethernet driver for NVIDIA nForce media access controllers. + * + * Note: This driver is a cleanroom reimplementation based on reverse + * engineered documentation written by Carl-Daniel Hailfinger + * and Andrew de Quincey. It's neither supported nor endorsed + * by NVIDIA Corp. Use at your own risk. + * + * NVIDIA, nForce and other NVIDIA marks are trademarks or registered + * trademarks of NVIDIA Corporation in the United States and other + * countries. + * + * Copyright (C) 2003 Manfred Spraul + * Copyright (C) 2004 Andrew de Quincey (wol support) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Changelog: + * 0.01: 05 Oct 2003: First release that compiles without warnings. + * 0.02: 05 Oct 2003: Fix bug for nv_drain_tx: do not try to free NULL skbs. + * Check all PCI BARs for the register window. + * udelay added to mii_rw. + * 0.03: 06 Oct 2003: Initialize dev->irq. + * 0.04: 07 Oct 2003: Initialize np->lock, reduce handled irqs, add printks. + * 0.05: 09 Oct 2003: printk removed again, irq status print tx_timeout. + * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, + * irq mask updated + * 0.07: 14 Oct 2003: Further irq mask updates. + * 0.08: 20 Oct 2003: rx_desc.Length initialization added, nv_alloc_rx refill + * added into irq handler, NULL check for drain_ring. + * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the + * requested interrupt sources. + * 0.10: 20 Oct 2003: First cleanup for release. + * 0.11: 21 Oct 2003: hexdump for tx added, rx buffer sizes increased. + * MAC Address init fix, set_multicast cleanup. + * 0.12: 23 Oct 2003: Cleanups for release. + * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. + * Set link speed correctly. start rx before starting + * tx (nv_start_rx sets the link speed). + * 0.14: 25 Oct 2003: Nic dependant irq mask. + * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during + * open. + * 0.16: 15 Nov 2003: include file cleanup for ppc64, rx buffer size + * increased to 1628 bytes. + * 0.17: 16 Nov 2003: undo rx buffer size increase. Substract 1 from + * the tx length. + * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats + * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac + * addresses, really stop rx if already running + * in nv_start_rx, clean up a bit. + * (C) Carl-Daniel Hailfinger + * 0.20: 07 Dec 2003: alloc fixes + * 0.21: 12 Jan 2004: additional alloc fix, nic polling fix. + * 0.22: 19 Jan 2004: reprogram timer to a sane rate, avoid lockup + * on close. + * (C) Carl-Daniel Hailfinger, Manfred Spraul + * 0.23: 26 Jan 2004: various small cleanups + * 0.24: 27 Feb 2004: make driver even less anonymous in backtraces + * 0.25: 09 Mar 2004: wol support + * + * Known bugs: + * We suspect that on some hardware no TX done interrupts are generated. + * This means recovery from netif_stop_queue only happens if the hw timer + * interrupt fires (100 times/second, configurable with NVREG_POLL_DEFAULT) + * and the timer is active in the IRQMask, or if a rx packet arrives by chance. + * If your hardware reliably generates tx done interrupts, then you can remove + * DEV_NEED_TIMERIRQ from the driver_data flags. + * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few + * superfluous timer interrupts from the nic. + */ +#define FORCEDETH_VERSION "0.25" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +#define dprintk printk +#else +#define dprintk(x...) do { } while (0) +#endif + + +/* + * Hardware access: + */ + +#define DEV_NEED_LASTPACKET1 0x0001 +#define DEV_IRQMASK_1 0x0002 +#define DEV_IRQMASK_2 0x0004 +#define DEV_NEED_TIMERIRQ 0x0008 + +enum { + NvRegIrqStatus = 0x000, +#define NVREG_IRQSTAT_MIIEVENT 0x040 +#define NVREG_IRQSTAT_MASK 0x1ff + NvRegIrqMask = 0x004, +#define NVREG_IRQ_RX 0x0002 +#define NVREG_IRQ_RX_NOBUF 0x0004 +#define NVREG_IRQ_TX_ERR 0x0008 +#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TIMER 0x0020 +#define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX1 0x0100 +#define NVREG_IRQMASK_WANTED_1 0x005f +#define NVREG_IRQMASK_WANTED_2 0x0147 +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) + + NvRegUnknownSetupReg6 = 0x008, +#define NVREG_UNKSETUP6_VAL 3 + +/* + * NVREG_POLL_DEFAULT is the interval length of the timer source on the nic + * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms + */ + NvRegPollingInterval = 0x00c, +#define NVREG_POLL_DEFAULT 970 + NvRegMisc1 = 0x080, +#define NVREG_MISC1_HD 0x02 +#define NVREG_MISC1_FORCE 0x3b0f3c + + NvRegTransmitterControl = 0x084, +#define NVREG_XMITCTL_START 0x01 + NvRegTransmitterStatus = 0x088, +#define NVREG_XMITSTAT_BUSY 0x01 + + NvRegPacketFilterFlags = 0x8c, +#define NVREG_PFF_ALWAYS 0x7F0008 +#define NVREG_PFF_PROMISC 0x80 +#define NVREG_PFF_MYADDR 0x20 + + NvRegOffloadConfig = 0x90, +#define NVREG_OFFLOAD_HOMEPHY 0x601 +#define NVREG_OFFLOAD_NORMAL 0x5ee + NvRegReceiverControl = 0x094, +#define NVREG_RCVCTL_START 0x01 + NvRegReceiverStatus = 0x98, +#define NVREG_RCVSTAT_BUSY 0x01 + + NvRegRandomSeed = 0x9c, +#define NVREG_RNDSEED_MASK 0x00ff +#define NVREG_RNDSEED_FORCE 0x7f00 + + NvRegUnknownSetupReg1 = 0xA0, +#define NVREG_UNKSETUP1_VAL 0x16070f + NvRegUnknownSetupReg2 = 0xA4, +#define NVREG_UNKSETUP2_VAL 0x16 + NvRegMacAddrA = 0xA8, + NvRegMacAddrB = 0xAC, + NvRegMulticastAddrA = 0xB0, +#define NVREG_MCASTADDRA_FORCE 0x01 + NvRegMulticastAddrB = 0xB4, + NvRegMulticastMaskA = 0xB8, + NvRegMulticastMaskB = 0xBC, + + NvRegTxRingPhysAddr = 0x100, + NvRegRxRingPhysAddr = 0x104, + NvRegRingSizes = 0x108, +#define NVREG_RINGSZ_TXSHIFT 0 +#define NVREG_RINGSZ_RXSHIFT 16 + NvRegUnknownTransmitterReg = 0x10c, + NvRegLinkSpeed = 0x110, +#define NVREG_LINKSPEED_FORCE 0x10000 +#define NVREG_LINKSPEED_10 10 +#define NVREG_LINKSPEED_100 100 +#define NVREG_LINKSPEED_1000 1000 + NvRegUnknownSetupReg5 = 0x130, +#define NVREG_UNKSETUP5_BIT31 (1<<31) + NvRegUnknownSetupReg3 = 0x134, +#define NVREG_UNKSETUP3_VAL1 0x200010 + NvRegTxRxControl = 0x144, +#define NVREG_TXRXCTL_KICK 0x0001 +#define NVREG_TXRXCTL_BIT1 0x0002 +#define NVREG_TXRXCTL_BIT2 0x0004 +#define NVREG_TXRXCTL_IDLE 0x0008 +#define NVREG_TXRXCTL_RESET 0x0010 + NvRegMIIStatus = 0x180, +#define NVREG_MIISTAT_ERROR 0x0001 +#define NVREG_MIISTAT_LINKCHANGE 0x0008 +#define NVREG_MIISTAT_MASK 0x000f +#define NVREG_MIISTAT_MASK2 0x000f + NvRegUnknownSetupReg4 = 0x184, +#define NVREG_UNKSETUP4_VAL 8 + + NvRegAdapterControl = 0x188, +#define NVREG_ADAPTCTL_START 0x02 +#define NVREG_ADAPTCTL_LINKUP 0x04 +#define NVREG_ADAPTCTL_PHYVALID 0x4000 +#define NVREG_ADAPTCTL_RUNNING 0x100000 +#define NVREG_ADAPTCTL_PHYSHIFT 24 + NvRegMIISpeed = 0x18c, +#define NVREG_MIISPEED_BIT8 (1<<8) +#define NVREG_MIIDELAY 5 + NvRegMIIControl = 0x190, +#define NVREG_MIICTL_INUSE 0x10000 +#define NVREG_MIICTL_WRITE 0x08000 +#define NVREG_MIICTL_ADDRSHIFT 5 + NvRegMIIData = 0x194, + NvRegWakeUpFlags = 0x200, +#define NVREG_WAKEUPFLAGS_VAL 0x7770 +#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24 +#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16 +#define NVREG_WAKEUPFLAGS_D3SHIFT 12 +#define NVREG_WAKEUPFLAGS_D2SHIFT 8 +#define NVREG_WAKEUPFLAGS_D1SHIFT 4 +#define NVREG_WAKEUPFLAGS_D0SHIFT 0 +#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 +#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 +#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 +#define NVREG_WAKEUPFLAGS_ENABLE 0x1111 + + NvRegPatternCRC = 0x204, + NvRegPatternMask = 0x208, + NvRegPowerCap = 0x268, +#define NVREG_POWERCAP_D3SUPP (1<<30) +#define NVREG_POWERCAP_D2SUPP (1<<26) +#define NVREG_POWERCAP_D1SUPP (1<<25) + NvRegPowerState = 0x26c, +#define NVREG_POWERSTATE_POWEREDUP 0x8000 +#define NVREG_POWERSTATE_VALID 0x0100 +#define NVREG_POWERSTATE_MASK 0x0003 +#define NVREG_POWERSTATE_D0 0x0000 +#define NVREG_POWERSTATE_D1 0x0001 +#define NVREG_POWERSTATE_D2 0x0002 +#define NVREG_POWERSTATE_D3 0x0003 +}; + +struct ring_desc { + u32 PacketBuffer; + u16 Length; + u16 Flags; +}; + +#define NV_TX_LASTPACKET (1<<0) +#define NV_TX_RETRYERROR (1<<3) +#define NV_TX_LASTPACKET1 (1<<8) +#define NV_TX_DEFERRED (1<<10) +#define NV_TX_CARRIERLOST (1<<11) +#define NV_TX_LATECOLLISION (1<<12) +#define NV_TX_UNDERFLOW (1<<13) +#define NV_TX_ERROR (1<<14) +#define NV_TX_VALID (1<<15) + +#define NV_RX_DESCRIPTORVALID (1<<0) +#define NV_RX_MISSEDFRAME (1<<1) +#define NV_RX_SUBSTRACT1 (1<<3) +#define NV_RX_ERROR1 (1<<7) +#define NV_RX_ERROR2 (1<<8) +#define NV_RX_ERROR3 (1<<9) +#define NV_RX_ERROR4 (1<<10) +#define NV_RX_CRCERR (1<<11) +#define NV_RX_OVERFLOW (1<<12) +#define NV_RX_FRAMINGERR (1<<13) +#define NV_RX_ERROR (1<<14) +#define NV_RX_AVAIL (1<<15) + +/* Miscelaneous hardware related defines: */ +#define NV_PCI_REGSZ 0x270 + +/* various timeout delays: all in usec */ +#define NV_TXRX_RESET_DELAY 4 +#define NV_TXSTOP_DELAY1 10 +#define NV_TXSTOP_DELAY1MAX 500000 +#define NV_TXSTOP_DELAY2 100 +#define NV_RXSTOP_DELAY1 10 +#define NV_RXSTOP_DELAY1MAX 500000 +#define NV_RXSTOP_DELAY2 100 +#define NV_SETUP5_DELAY 5 +#define NV_SETUP5_DELAYMAX 50000 +#define NV_POWERUP_DELAY 5 +#define NV_POWERUP_DELAYMAX 5000 +#define NV_MIIBUSY_DELAY 50 +#define NV_MIIPHY_DELAY 10 +#define NV_MIIPHY_DELAYMAX 10000 + +#define NV_WAKEUPPATTERNS 5 +#define NV_WAKEUPMASKENTRIES 4 + +/* General driver defaults */ +#define NV_WATCHDOG_TIMEO (5*HZ) +#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */ + +#define RX_RING 128 +#define TX_RING 16 +/* limited to 1 packet until we understand NV_TX_LASTPACKET */ +#define TX_LIMIT_STOP 10 +#define TX_LIMIT_START 5 + +/* rx/tx mac addr + type + vlan + align + slack*/ +#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64) +/* even more slack */ +#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128) + +#define OOM_REFILL (1+HZ/20) +#define POLL_WAIT (1+HZ/100) + +/* + * SMP locking: + * All hardware access under dev->priv->lock, except the performance + * critical parts: + * - rx is (pseudo-) lockless: it relies on the single-threading provided + * by the arch code for interrupts. + * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission + * needs dev->priv->lock :-( + * - set_multicast_list: preparation lockless, relies on dev->xmit_lock. + */ + +/* in dev: base, irq */ +struct fe_priv { + spinlock_t lock; + + /* General data: + * Locking: spin_lock(&np->lock); */ + struct net_device_stats stats; + int in_shutdown; + u32 linkspeed; + int duplex; + int phyaddr; + int wolenabled; + + /* General data: RO fields */ + dma_addr_t ring_addr; + struct pci_dev *pci_dev; + u32 orig_mac[2]; + u32 irqmask; + + /* rx specific fields. + * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); + */ + struct ring_desc *rx_ring; + unsigned int cur_rx, refill_rx; + struct sk_buff *rx_skbuff[RX_RING]; + dma_addr_t rx_dma[RX_RING]; + unsigned int rx_buf_sz; + struct timer_list oom_kick; + struct timer_list nic_poll; + + /* + * tx specific fields. + */ + struct ring_desc *tx_ring; + unsigned int next_tx, nic_tx; + struct sk_buff *tx_skbuff[TX_RING]; + dma_addr_t tx_dma[TX_RING]; + u16 tx_flags; +}; + +/* + * Maximum number of loops until we assume that a bit in the irq mask + * is stuck. Overridable with module param. + */ +static int max_interrupt_work = 5; + +static inline struct fe_priv *get_nvpriv(struct net_device *dev) +{ + return (struct fe_priv *) dev->priv; +} + +static inline u8 *get_hwbase(struct net_device *dev) +{ + return (u8 *) dev->base_addr; +} + +static inline void pci_push(u8 * base) +{ + /* force out pending posted writes */ + readl(base); +} + +static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, + int delay, int delaymax, const char *msg) +{ + u8 *base = get_hwbase(dev); + + pci_push(base); + do { + udelay(delay); + delaymax -= delay; + if (delaymax < 0) { + if (msg) + printk(msg); + return 1; + } + } while ((readl(base + offset) & mask) != target); + return 0; +} + +#define MII_READ (-1) +/* mii_rw: read/write a register on the PHY. + * + * Caller must guarantee serialization + */ +static int mii_rw(struct net_device *dev, int addr, int miireg, int value) +{ + u8 *base = get_hwbase(dev); + int was_running; + u32 reg; + int retval; + + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + was_running = 0; + reg = readl(base + NvRegAdapterControl); + if (reg & NVREG_ADAPTCTL_RUNNING) { + was_running = 1; + writel(reg & ~NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + reg = readl(base + NvRegMIIControl); + if (reg & NVREG_MIICTL_INUSE) { + writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl); + udelay(NV_MIIBUSY_DELAY); + } + + reg = NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg; + if (value != MII_READ) { + writel(value, base + NvRegMIIData); + reg |= NVREG_MIICTL_WRITE; + } + writel(reg, base + NvRegMIIControl); + + if (reg_delay(dev, NvRegMIIControl, NVREG_MIICTL_INUSE, 0, + NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, NULL)) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d timed out.\n", + dev->name, miireg, addr); + retval = -1; + } else if (value != MII_READ) { + /* it was a write operation - fewer failures are detectable */ + dprintk(KERN_DEBUG "%s: mii_rw wrote 0x%x to reg %d at PHY %d\n", + dev->name, value, miireg, addr); + retval = 0; + } else if (readl(base + NvRegMIIStatus) & NVREG_MIISTAT_ERROR) { + dprintk(KERN_DEBUG "%s: mii_rw of reg %d at PHY %d failed.\n", + dev->name, miireg, addr); + retval = -1; + } else { + /* FIXME: why is that required? */ + udelay(50); + retval = readl(base + NvRegMIIData); + dprintk(KERN_DEBUG "%s: mii_rw read from reg %d at PHY %d: 0x%x.\n", + dev->name, miireg, addr, retval); + } + if (was_running) { + reg = readl(base + NvRegAdapterControl); + writel(reg | NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + } + return retval; +} + +static void nv_start_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); + /* Already running? Stop it. */ + if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { + writel(0, base + NvRegReceiverControl); + pci_push(base); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + writel(NVREG_RCVCTL_START, base + NvRegReceiverControl); + pci_push(base); +} + +static void nv_stop_rx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); + writel(0, base + NvRegReceiverControl); + reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, + NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, + KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); + + udelay(NV_RXSTOP_DELAY2); + writel(0, base + NvRegLinkSpeed); +} + +static void nv_start_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name); + writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); + pci_push(base); +} + +static void nv_stop_tx(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); + writel(0, base + NvRegTransmitterControl); + reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, + NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, + KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); + + udelay(NV_TXSTOP_DELAY2); + writel(0, base + NvRegUnknownTransmitterReg); +} + +static void nv_txrx_reset(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); + pci_push(base); + udelay(NV_TXRX_RESET_DELAY); + writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl); + pci_push(base); +} + +/* + * nv_get_stats: dev->get_stats function + * Get latest stats value from the nic. + * Called with read_lock(&dev_base_lock) held for read - + * only synchronized against unregister_netdevice. + */ +static struct net_device_stats *nv_get_stats(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + /* It seems that the nic always generates interrupts and doesn't + * accumulate errors internally. Thus the current values in np->stats + * are already up to date. + */ + return &np->stats; +} + +static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 ethcmd; + + if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy(info.driver, "forcedeth"); + strcpy(info.version, FORCEDETH_VERSION); + strcpy(info.bus_info, pci_name(np->pci_dev)); + if (copy_to_user(useraddr, &info, sizeof (info))) + return -EFAULT; + return 0; + } + case ETHTOOL_GLINK: + { + struct ethtool_value edata = { ETHTOOL_GLINK }; + + edata.data = !!netif_carrier_ok(dev); + + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_GWOL: + { + struct ethtool_wolinfo wolinfo; + memset(&wolinfo, 0, sizeof(wolinfo)); + wolinfo.supported = WAKE_MAGIC; + + spin_lock_irq(&np->lock); + if (np->wolenabled) + wolinfo.wolopts = WAKE_MAGIC; + spin_unlock_irq(&np->lock); + + if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: + { + struct ethtool_wolinfo wolinfo; + if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo))) + return -EFAULT; + + spin_lock_irq(&np->lock); + if (wolinfo.wolopts == 0) { + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; + } + if (wolinfo.wolopts & WAKE_MAGIC) { + writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags); + np->wolenabled = 1; + } + spin_unlock_irq(&np->lock); + return 0; + } + + default: + break; + } + + return -EOPNOTSUPP; +} +/* + * nv_ioctl: dev->do_ioctl function + * Called with rtnl_lock held. + */ +static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + switch(cmd) { + case SIOCETHTOOL: + return nv_ethtool_ioctl(dev, (void *) rq->ifr_data); + + default: + return -EOPNOTSUPP; + } +} + +/* + * nv_alloc_rx: fill rx ring entries. + * Return 1 if the allocations for the skbs failed and the + * rx engine is without Available descriptors + */ +static int nv_alloc_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + unsigned int refill_rx = np->refill_rx; + + while (np->cur_rx != refill_rx) { + int nr = refill_rx % RX_RING; + struct sk_buff *skb; + + if (np->rx_skbuff[nr] == NULL) { + + skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + if (!skb) + break; + + skb->dev = dev; + np->rx_skbuff[nr] = skb; + } else { + skb = np->rx_skbuff[nr]; + } + np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, + PCI_DMA_FROMDEVICE); + np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); + wmb(); + np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); + dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", + dev->name, refill_rx); + refill_rx++; + } + np->refill_rx = refill_rx; + if (np->cur_rx - refill_rx == RX_RING) + return 1; + return 0; +} + +static void nv_do_rx_refill(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + + disable_irq(dev->irq); + if (nv_alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + enable_irq(dev->irq); +} + +static int nv_init_ring(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + } + + np->cur_rx = RX_RING; + np->refill_rx = 0; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + } + return nv_alloc_rx(dev); +} + +static void nv_drain_tx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < TX_RING; i++) { + np->tx_ring[i].Flags = 0; + if (np->tx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->stats.tx_dropped++; + } + } +} + +static void nv_drain_rx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + for (i = 0; i < RX_RING; i++) { + np->rx_ring[i].Flags = 0; + wmb(); + if (np->rx_skbuff[i]) { + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_skbuff[i]); + np->rx_skbuff[i] = NULL; + } + } +} + +static void drain_ring(struct net_device *dev) +{ + nv_drain_tx(dev); + nv_drain_rx(dev); +} + +/* + * nv_start_xmit: dev->hard_start_xmit function + * Called with dev->xmit_lock held. + */ +static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int nr = np->next_tx % TX_RING; + + np->tx_skbuff[nr] = skb; + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, + PCI_DMA_TODEVICE); + + np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring[nr].Length = cpu_to_le16(skb->len-1); + + spin_lock_irq(&np->lock); + wmb(); + np->tx_ring[nr].Flags = np->tx_flags; + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", + dev->name, np->next_tx); + { + int j; + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + + np->next_tx++; + + dev->trans_start = jiffies; + if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) + netif_stop_queue(dev); + spin_unlock_irq(&np->lock); + writel(NVREG_TXRXCTL_KICK, get_hwbase(dev) + NvRegTxRxControl); + pci_push(get_hwbase(dev)); + return 0; +} + +/* + * nv_tx_done: check for completed packets, release the skbs. + * + * Caller must own np->lock. + */ +static void nv_tx_done(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + while (np->nic_tx < np->next_tx) { + struct ring_desc *prd; + int i = np->nic_tx % TX_RING; + + prd = &np->tx_ring[i]; + + dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", + dev->name, np->nic_tx, prd->Flags); + if (prd->Flags & cpu_to_le16(NV_TX_VALID)) + break; + if (prd->Flags & cpu_to_le16(NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (prd->Flags & cpu_to_le16(NV_TX_UNDERFLOW)) + np->stats.tx_fifo_errors++; + if (prd->Flags & cpu_to_le16(NV_TX_CARRIERLOST)) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += np->tx_skbuff[i]->len; + } + pci_unmap_single(np->pci_dev, np->tx_dma[i], + np->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(np->tx_skbuff[i]); + np->tx_skbuff[i] = NULL; + np->nic_tx++; + } + if (np->next_tx - np->nic_tx < TX_LIMIT_START) + netif_wake_queue(dev); +} + +/* + * nv_tx_timeout: dev->tx_timeout function + * Called with dev->xmit_lock held. + */ +static void nv_tx_timeout(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + + spin_lock_irq(&np->lock); + + /* 1) stop tx engine */ + nv_stop_tx(dev); + + /* 2) check that the packets were not sent already: */ + nv_tx_done(dev); + + /* 3) if there are dead entries: clear everything */ + if (np->next_tx != np->nic_tx) { + printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); + nv_drain_tx(dev); + np->next_tx = np->nic_tx = 0; + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + netif_wake_queue(dev); + } + + /* 4) restart tx engine */ + nv_start_tx(dev); + spin_unlock_irq(&np->lock); +} + +static void nv_rx_process(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + + for (;;) { + struct ring_desc *prd; + struct sk_buff *skb; + int len; + int i; + if (np->cur_rx - np->refill_rx >= RX_RING) + break; /* we scanned the whole ring - do not continue */ + + i = np->cur_rx % RX_RING; + prd = &np->rx_ring[i]; + dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", + dev->name, np->cur_rx, prd->Flags); + + if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) + break; /* still owned by hardware, */ + + /* + * the packet is for us - immediately tear down the pci mapping. + * TODO: check if a prefetch of the first cacheline improves + * the performance. + */ + pci_unmap_single(np->pci_dev, np->rx_dma[i], + np->rx_skbuff[i]->len, + PCI_DMA_FROMDEVICE); + + { + int j; + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",prd->Flags); + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]); + } + dprintk("\n"); + } + /* look at what we actually got: */ + if (!(prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID))) + goto next_pkt; + + + len = le16_to_cpu(prd->Length); + + if (prd->Flags & cpu_to_le16(NV_RX_MISSEDFRAME)) { + np->stats.rx_missed_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_CRCERR)) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_OVERFLOW)) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (prd->Flags & cpu_to_le16(NV_RX_ERROR)) { + /* framing errors are soft errors, the rest is fatal. */ + if (prd->Flags & cpu_to_le16(NV_RX_FRAMINGERR)) { + if (prd->Flags & cpu_to_le16(NV_RX_SUBSTRACT1)) { + len--; + } + } else { + np->stats.rx_errors++; + goto next_pkt; + } + } + /* got a valid packet - forward it to the network core */ + skb = np->rx_skbuff[i]; + np->rx_skbuff[i] = NULL; + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", + dev->name, np->cur_rx, len, skb->protocol); + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; +next_pkt: + np->cur_rx++; + } +} + +/* + * nv_change_mtu: dev->change_mtu function + * Called with dev_base_lock held for read. + */ +static int nv_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu > DEFAULT_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +/* + * nv_set_multicast: dev->set_multicast function + * Called with dev->xmit_lock held. + */ +static void nv_set_multicast(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 addr[2]; + u32 mask[2]; + u32 pff; + + memset(addr, 0, sizeof(addr)); + memset(mask, 0, sizeof(mask)); + + if (dev->flags & IFF_PROMISC) { + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + pff = NVREG_PFF_PROMISC; + } else { + pff = NVREG_PFF_MYADDR; + + if (dev->flags & IFF_ALLMULTI || dev->mc_list) { + u32 alwaysOff[2]; + u32 alwaysOn[2]; + + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0xffffffff; + if (dev->flags & IFF_ALLMULTI) { + alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; + } else { + struct dev_mc_list *walk; + + walk = dev->mc_list; + while (walk != NULL) { + u32 a, b; + a = le32_to_cpu(*(u32 *) walk->dmi_addr); + b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4])); + alwaysOn[0] &= a; + alwaysOff[0] &= ~a; + alwaysOn[1] &= b; + alwaysOff[1] &= ~b; + walk = walk->next; + } + } + addr[0] = alwaysOn[0]; + addr[1] = alwaysOn[1]; + mask[0] = alwaysOn[0] | alwaysOff[0]; + mask[1] = alwaysOn[1] | alwaysOff[1]; + } + } + addr[0] |= NVREG_MCASTADDRA_FORCE; + pff |= NVREG_PFF_ALWAYS; + spin_lock_irq(&np->lock); + nv_stop_rx(dev); + writel(addr[0], base + NvRegMulticastAddrA); + writel(addr[1], base + NvRegMulticastAddrB); + writel(mask[0], base + NvRegMulticastMaskA); + writel(mask[1], base + NvRegMulticastMaskB); + writel(pff, base + NvRegPacketFilterFlags); + nv_start_rx(dev); + spin_unlock_irq(&np->lock); +} + +static int nv_update_linkspeed(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int adv, lpa, newls, newdup; + + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", + dev->name, adv, lpa); + + /* FIXME: handle parallel detection properly, handle gigabit ethernet */ + lpa = lpa & adv; + if (lpa & LPA_100FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 1; + } else if (lpa & LPA_100HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 0; + } else if (lpa & LPA_10FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 1; + } else if (lpa & LPA_10HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } else { + dprintk(KERN_DEBUG "%s: bad ability %04x - falling back to 10HD.\n", dev->name, lpa); + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } + if (np->duplex != newdup || np->linkspeed != newls) { + np->duplex = newdup; + np->linkspeed = newls; + return 1; + } + return 0; +} + +static void nv_link_irq(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 miistat; + int miival; + + miistat = readl(base + NvRegMIIStatus); + writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); + printk(KERN_DEBUG "%s: link change notification, status 0x%x.\n", dev->name, miistat); + + miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); + if (miival & BMSR_ANEGCOMPLETE) { + nv_update_linkspeed(dev); + + if (netif_carrier_ok(dev)) { + nv_stop_rx(dev); + } else { + netif_carrier_on(dev); + printk(KERN_INFO "%s: link up.\n", dev->name); + } + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + nv_start_rx(dev); + } else { + if (netif_carrier_ok(dev)) { + netif_carrier_off(dev); + printk(KERN_INFO "%s: link down.\n", dev->name); + nv_stop_rx(dev); + } + writel(np->linkspeed, base + NvRegLinkSpeed); + pci_push(base); + } +} + +static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + spin_lock(&np->lock); + nv_tx_done(dev); + spin_unlock(&np->lock); + } + + if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { + nv_rx_process(dev); + if (nv_alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } + + if (events & NVREG_IRQ_LINK) { + spin_lock(&np->lock); + nv_link_irq(dev); + spin_unlock(&np->lock); + } + if (events & (NVREG_IRQ_TX_ERR)) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (events & (NVREG_IRQ_UNKNOWN)) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(0, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +static void nv_do_nic_poll(unsigned long data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + disable_irq(dev->irq); + /* FIXME: Do we need synchronize_irq(dev->irq) here? */ + /* + * reenable interrupts on the nic, we have to do this before calling + * nv_nic_irq because that may decide to do otherwise + */ + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(dev->irq); +} + +static int nv_open(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + int ret, oom, i; + + dprintk(KERN_DEBUG "nv_open: begin\n"); + + /* 1) erase previous misconfiguration */ + /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */ + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(0, base + NvRegPacketFilterFlags); + writel(0, base + NvRegAdapterControl); + writel(0, base + NvRegLinkSpeed); + writel(0, base + NvRegUnknownTransmitterReg); + nv_txrx_reset(dev); + writel(0, base + NvRegUnknownSetupReg6); + + /* 2) initialize descriptor rings */ + np->in_shutdown = 0; + oom = nv_init_ring(dev); + + /* 3) set mac address */ + { + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); + } + + /* 4) continue setup */ + np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + np->duplex = 0; + writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); + writel(0, base + NvRegTxRxControl); + pci_push(base); + writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl); + reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, + NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, + KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); + writel(0, base + NvRegUnknownSetupReg4); + + /* 5) Find a suitable PHY */ + writel(NVREG_MIISPEED_BIT8|NVREG_MIIDELAY, base + NvRegMIISpeed); + for (i = 1; i < 32; i++) { + int id1, id2; + + spin_lock_irq(&np->lock); + id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); + spin_unlock_irq(&np->lock); + if (id1 < 0 || id1 == 0xffff) + continue; + spin_lock_irq(&np->lock); + id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); + spin_unlock_irq(&np->lock); + if (id2 < 0 || id2 == 0xffff) + continue; + dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", + dev->name, id1, id2, i); + np->phyaddr = i; + + spin_lock_irq(&np->lock); + nv_update_linkspeed(dev); + spin_unlock_irq(&np->lock); + + break; + } + if (i == 32) { + printk(KERN_INFO "%s: open: failing due to lack of suitable PHY.\n", + dev->name); + ret = -EINVAL; + goto out_drain; + } + + /* 6) continue setup */ + writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), + base + NvRegMisc1); + writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); + writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); + writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + + writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); + get_random_bytes(&i, sizeof(i)); + writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); + writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); + writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); + writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); + writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); + writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID, + base + NvRegAdapterControl); + writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4); + writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags); + + /* 7) start packet processing */ + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + + i = readl(base + NvRegPowerState); + if ( (i & NVREG_POWERSTATE_POWEREDUP) == 0) + writel(NVREG_POWERSTATE_POWEREDUP|i, base + NvRegPowerState); + + pci_push(base); + udelay(10); + writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID, base + NvRegPowerState); + writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); + + + writel(0, base + NvRegIrqMask); + pci_push(base); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus); + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + pci_push(base); + + ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev); + if (ret) + goto out_drain; + + writel(np->irqmask, base + NvRegIrqMask); + + spin_lock_irq(&np->lock); + writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA); + writel(0, base + NvRegMulticastAddrB); + writel(0, base + NvRegMulticastMaskA); + writel(0, base + NvRegMulticastMaskB); + writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); + nv_start_rx(dev); + nv_start_tx(dev); + netif_start_queue(dev); + if (oom) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + if (mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ) & BMSR_ANEGCOMPLETE) { + netif_carrier_on(dev); + } else { + printk("%s: no link during initialization.\n", dev->name); + netif_carrier_off(dev); + } + + spin_unlock_irq(&np->lock); + + return 0; +out_drain: + drain_ring(dev); + return ret; +} + +static int nv_close(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 *base; + + spin_lock_irq(&np->lock); + np->in_shutdown = 1; + spin_unlock_irq(&np->lock); + synchronize_irq(); + + del_timer_sync(&np->oom_kick); + del_timer_sync(&np->nic_poll); + + netif_stop_queue(dev); + spin_lock_irq(&np->lock); + nv_stop_tx(dev); + nv_stop_rx(dev); + base = get_hwbase(dev); + + /* disable interrupts on the nic or we will lock up */ + writel(0, base + NvRegIrqMask); + pci_push(base); + dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); + + spin_unlock_irq(&np->lock); + + free_irq(dev->irq, dev); + + drain_ring(dev); + + if (np->wolenabled) + nv_start_rx(dev); + + /* FIXME: power down nic */ + + return 0; +} + +static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) +{ + struct net_device *dev; + struct fe_priv *np; + unsigned long addr; + u8 *base; + int err, i; + + dev = alloc_etherdev(sizeof(struct fe_priv)); + err = -ENOMEM; + if (!dev) + goto out; + + np = get_nvpriv(dev); + np->pci_dev = pci_dev; + spin_lock_init(&np->lock); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pci_dev->dev); + + init_timer(&np->oom_kick); + np->oom_kick.data = (unsigned long) dev; + np->oom_kick.function = &nv_do_rx_refill; /* timer handler */ + init_timer(&np->nic_poll); + np->nic_poll.data = (unsigned long) dev; + np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_INFO "forcedeth: pci_enable_dev failed (%d) for device %s\n", + err, pci_name(pci_dev)); + goto out_free; + } + + pci_set_master(pci_dev); + + err = pci_request_regions(pci_dev, dev->name); + if (err < 0) + goto out_disable; + + err = -EINVAL; + addr = 0; + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dprintk(KERN_DEBUG "%s: resource %d start %p len %ld flags 0x%08lx.\n", + pci_name(pci_dev), i, (void*)pci_resource_start(pci_dev, i), + pci_resource_len(pci_dev, i), + pci_resource_flags(pci_dev, i)); + if (pci_resource_flags(pci_dev, i) & IORESOURCE_MEM && + pci_resource_len(pci_dev, i) >= NV_PCI_REGSZ) { + addr = pci_resource_start(pci_dev, i); + break; + } + } + if (i == DEVICE_COUNT_RESOURCE) { + printk(KERN_INFO "forcedeth: Couldn't find register window for device %s.\n", + pci_name(pci_dev)); + goto out_relreg; + } + + err = -ENOMEM; + dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); + if (!dev->base_addr) + goto out_relreg; + dev->irq = pci_dev->irq; + np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring) + goto out_unmap; + np->tx_ring = &np->rx_ring[RX_RING]; + + dev->open = nv_open; + dev->stop = nv_close; + dev->hard_start_xmit = nv_start_xmit; + dev->get_stats = nv_get_stats; + dev->change_mtu = nv_change_mtu; + dev->set_multicast_list = nv_set_multicast; + dev->do_ioctl = nv_ioctl; + dev->tx_timeout = nv_tx_timeout; + dev->watchdog_timeo = NV_WATCHDOG_TIMEO; + + pci_set_drvdata(pci_dev, dev); + + /* read the mac address */ + base = get_hwbase(dev); + np->orig_mac[0] = readl(base + NvRegMacAddrA); + np->orig_mac[1] = readl(base + NvRegMacAddrB); + + dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff; + dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff; + dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff; + dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; + dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; + dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; + + if (!is_valid_ether_addr(dev->dev_addr)) { + /* + * Bad mac address. At least one bios sets the mac address + * to 01:23:45:67:89:ab + */ + printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n", + pci_name(pci_dev), + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n"); + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x6c; + get_random_bytes(&dev->dev_addr[3], 3); + } + + dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + /* disable WOL */ + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; + + np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); + if (id->driver_data & DEV_NEED_LASTPACKET1) + np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1); + if (id->driver_data & DEV_IRQMASK_1) + np->irqmask = NVREG_IRQMASK_WANTED_1; + if (id->driver_data & DEV_IRQMASK_2) + np->irqmask = NVREG_IRQMASK_WANTED_2; + if (id->driver_data & DEV_NEED_TIMERIRQ) + np->irqmask |= NVREG_IRQ_TIMER; + + err = register_netdev(dev); + if (err) { + printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err); + goto out_freering; + } + printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n", + dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device, + pci_name(pci_dev)); + + return 0; + +out_freering: + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring, np->ring_addr); + pci_set_drvdata(pci_dev, NULL); +out_unmap: + iounmap(get_hwbase(dev)); +out_relreg: + pci_release_regions(pci_dev); +out_disable: + pci_disable_device(pci_dev); +out_free: + free_netdev(dev); +out: + return err; +} + +static void __devexit nv_remove(struct pci_dev *pci_dev) +{ + struct net_device *dev = pci_get_drvdata(pci_dev); + struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); + + unregister_netdev(dev); + + /* special op: write back the misordered MAC address - otherwise + * the next nv_probe would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + + /* free all structures */ + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + iounmap(get_hwbase(dev)); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + free_netdev(dev); + pci_set_drvdata(pci_dev, NULL); +} + +static struct pci_device_id pci_tbl[] = { + { /* nForce Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x1C3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ, + }, + { /* nForce2 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x0066, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + { /* nForce3 Ethernet Controller */ + .vendor = PCI_VENDOR_ID_NVIDIA, + .device = 0x00D6, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + }, + {0,}, +}; + +static struct pci_driver driver = { + .name = "forcedeth", + .id_table = pci_tbl, + .probe = nv_probe, + .remove = __devexit_p(nv_remove), +}; + + +static int __init init_nic(void) +{ + printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION); + return pci_module_init(&driver); +} + +static void __exit exit_nic(void) +{ + pci_unregister_driver(&driver); +} + +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); + +MODULE_AUTHOR("Manfred Spraul "); +MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(pci, pci_tbl); + +module_init(init_nic); +module_exit(exit_nic); diff -urN linux-2.4.25/drivers/net/ibm_emac/ibm_emac.h linux-2.4.26/drivers/net/ibm_emac/ibm_emac.h --- linux-2.4.25/drivers/net/ibm_emac/ibm_emac.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/ibm_emac/ibm_emac.h 2004-04-14 06:05:30.000000000 -0700 @@ -58,8 +58,8 @@ u32 em0gaht2; u32 em0gaht3; u32 em0gaht4; - u32 em0lsal; u32 em0lsah; + u32 em0lsal; u32 em0ipgvr; u32 em0stacr; u32 em0trtr; @@ -99,8 +99,8 @@ #define EMAC_M1_TX_FIFO_1K 0x00010000 #define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */ #define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */ -#define EMAC_M1_OPB_CLK_66 0x00000010 /* 66Mhz */ -#define EMAC_M1_OPB_CLK_83 0x00000008 /* 83hz */ +#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */ +#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */ #define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */ #define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */ #else /* CONFIG_IBM_EMAC4 */ diff -urN linux-2.4.25/drivers/net/ibm_emac/ibm_ocp_enet.c linux-2.4.26/drivers/net/ibm_emac/ibm_ocp_enet.c --- linux-2.4.25/drivers/net/ibm_emac/ibm_ocp_enet.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/ibm_emac/ibm_ocp_enet.c 2004-04-14 06:05:30.000000000 -0700 @@ -743,19 +743,19 @@ { struct ocp_enet_private *fep = dev->priv; volatile emac_t *emacp = fep->emacp; - + u32 rmr = in_be32(&emacp->em0rmr); + + /* First clear all special bits, they can be set later */ + rmr &= ~(EMAC_RMR_PME | EMAC_RMR_PMME | EMAC_RMR_MAE); + if (dev->flags & IFF_PROMISC) { - - /* If promiscuous mode is set then we do not need anything else */ - out_be32(&emacp->em0rmr, EMAC_RMR_PME); + rmr |= EMAC_RMR_PME; } else if (dev->flags & IFF_ALLMULTI || 32 < dev->mc_count) { - /* Must be setting up to use multicast. Now check for promiscuous * multicast */ - out_be32(&emacp->em0rmr, - EMAC_RMR_IAE | EMAC_RMR_BAE | EMAC_RMR_PMME); + rmr |= EMAC_RMR_PMME; } else if (dev->flags & IFF_MULTICAST && 0 < dev->mc_count) { unsigned short em0gaht[4] = { 0, 0, 0, 0 }; @@ -777,16 +777,10 @@ emacp->em0gaht4 = em0gaht[3]; /* Turn on multicast addressing */ - out_be32(&emacp->em0rmr, - EMAC_RMR_IAE | EMAC_RMR_BAE | EMAC_RMR_MAE); - - } else { - /* If multicast mode is not set then we are - * turning it off at this point - */ - out_be32(&emacp->em0rmr, EMAC_RMR_IAE | EMAC_RMR_BAE); - + rmr |= EMAC_RMR_MAE; } + + out_be32(&emacp->em0rmr, rmr); } static void diff -urN linux-2.4.25/drivers/net/ibm_emac/ibm_ocp_mal.c linux-2.4.26/drivers/net/ibm_emac/ibm_ocp_mal.c --- linux-2.4.25/drivers/net/ibm_emac/ibm_ocp_mal.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/ibm_emac/ibm_ocp_mal.c 2004-04-14 06:05:30.000000000 -0700 @@ -62,7 +62,7 @@ /* Don't let multiple commacs claim the same channel */ if ( (mal->tx_chan_mask & commac->tx_chan_mask) || (mal->rx_chan_mask & commac->rx_chan_mask) ) { - write_unlock(&mal_list_lock); + write_unlock_irqrestore(&mal_list_lock, flags); return -EBUSY; } diff -urN linux-2.4.25/drivers/net/natsemi.c linux-2.4.26/drivers/net/natsemi.c --- linux-2.4.25/drivers/net/natsemi.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/natsemi.c 2004-04-14 06:05:30.000000000 -0700 @@ -175,6 +175,8 @@ #define DRV_VERSION "1.07+LK1.0.17" #define DRV_RELDATE "Sep 27, 2002" +#define RX_OFFSET 2 + /* Updated to recommendations in pci-skeleton v2.03. */ /* The user-configurable values. @@ -1466,13 +1468,14 @@ struct sk_buff *skb; int entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; + skb = dev_alloc_skb(buflen); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->data, skb->len, PCI_DMA_FROMDEVICE); + skb->tail, buflen, PCI_DMA_FROMDEVICE); np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); } np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz); @@ -1542,6 +1545,7 @@ static void drain_ring(struct net_device *dev) { struct netdev_private *np = dev->priv; + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; int i; /* Free all the skbuffs in the Rx queue. */ @@ -1550,7 +1554,7 @@ np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, - np->rx_dma[i], np->rx_skbuff[i]->len, + np->rx_dma[i], buflen, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); } @@ -1746,6 +1750,7 @@ int entry = np->cur_rx % RX_RING_SIZE; int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status); + unsigned int buflen = np->rx_buf_sz + RX_OFFSET; /* If the driver owns the next entry it's a new packet. Send it up. */ while (desc_status < 0) { /* e.g. & DescOwn */ @@ -1784,13 +1789,13 @@ /* Check if the packet is long enough to accept * without copying to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { skb->dev = dev; /* 16 byte align the IP header */ - skb_reserve(skb, 2); + skb_reserve(skb, RX_OFFSET); pci_dma_sync_single(np->pci_dev, np->rx_dma[entry], - np->rx_skbuff[entry]->len, + buflen, PCI_DMA_FROMDEVICE); #if HAS_IP_COPYSUM eth_copy_and_sum(skb, @@ -1802,8 +1807,7 @@ #endif } else { pci_unmap_single(np->pci_dev, np->rx_dma[entry], - np->rx_skbuff[entry]->len, - PCI_DMA_FROMDEVICE); + buflen, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } diff -urN linux-2.4.25/drivers/net/ne2k-pci.c linux-2.4.26/drivers/net/ne2k-pci.c --- linux-2.4.25/drivers/net/ne2k-pci.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/ne2k-pci.c 2004-04-14 06:05:30.000000000 -0700 @@ -116,6 +116,7 @@ CH_Winbond_W89C940F, CH_Holtek_HT80232, CH_Holtek_HT80229, + CH_Winbond_89C940_8c4a, }; @@ -133,6 +134,7 @@ {"Winbond W89C940F", 0}, {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX}, {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 }, + {"Winbond W89C940(misprogrammed)", 0}, {0,} }; @@ -148,6 +150,7 @@ { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F }, { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 }, { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 }, + { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a }, { 0, } }; MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl); diff -urN linux-2.4.25/drivers/net/pcnet32.c linux-2.4.26/drivers/net/pcnet32.c --- linux-2.4.25/drivers/net/pcnet32.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/pcnet32.c 2004-04-14 06:05:30.000000000 -0700 @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.27a" -#define DRV_RELDATE "10.02.2002" +#define DRV_VERSION "1.28" +#define DRV_RELDATE "02.20.2004" #define PFX DRV_NAME ": " static const char *version = @@ -61,12 +61,18 @@ static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* + * Adapters that were sold with IBM's RS/6000 or pSeries hardware have + * the incorrect vendor id. + */ + { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0 }, { 0, } }; MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); -int cards_found __initdata; +static int cards_found __devinitdata; /* * VLB I/O addresses @@ -76,7 +82,7 @@ -static int pcnet32_debug = 1; +static int pcnet32_debug = 0; static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ static int pcnet32vlb; /* check for VLB cards ? */ @@ -120,6 +126,11 @@ PCNET32_PORT_ASEL /* 15 not supported */ }; +static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { + "Loopback test (offline)" +}; +#define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) + #define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; @@ -212,6 +223,13 @@ * fix pci probe not increment cards_found * FD auto negotiate error workaround for xSeries250 * clean up and using new mii module + * v1.28 20 Feb 2004 Don Fry + * Jon Mason , Chinmay Albal + * Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl. + * Fixes bogus 'Bus master arbitration failure', pci_[un]map_single + * length errors, and transmit hangs. Cleans up after errors in open. + * Jim Lewis added ethernet loopback test. + * Thomas Munck Steenholdt non-mii ioctl corrections. */ @@ -319,6 +337,7 @@ mii:1; /* mii port available */ struct net_device *next; struct mii_if_info mii_if; + u32 msg_enable; /* debug message level */ }; static void pcnet32_probe_vlbus(void); @@ -336,6 +355,10 @@ static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *dev, int phy_id, int reg_num); static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val); +static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); +static void pcnet32_ethtool_test(struct net_device *dev, + struct ethtool_test *eth_test, u64 *data); +static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1); enum pci_flags_bit { PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, @@ -389,13 +412,13 @@ } static struct pcnet32_access pcnet32_wio = { - read_csr: pcnet32_wio_read_csr, - write_csr: pcnet32_wio_write_csr, - read_bcr: pcnet32_wio_read_bcr, - write_bcr: pcnet32_wio_write_bcr, - read_rap: pcnet32_wio_read_rap, - write_rap: pcnet32_wio_write_rap, - reset: pcnet32_wio_reset + .read_csr = pcnet32_wio_read_csr, + .write_csr = pcnet32_wio_write_csr, + .read_bcr = pcnet32_wio_read_bcr, + .write_bcr = pcnet32_wio_write_bcr, + .read_rap = pcnet32_wio_read_rap, + .write_rap = pcnet32_wio_write_rap, + .reset = pcnet32_wio_reset }; static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) @@ -444,17 +467,283 @@ } static struct pcnet32_access pcnet32_dwio = { - read_csr: pcnet32_dwio_read_csr, - write_csr: pcnet32_dwio_write_csr, - read_bcr: pcnet32_dwio_read_bcr, - write_bcr: pcnet32_dwio_write_bcr, - read_rap: pcnet32_dwio_read_rap, - write_rap: pcnet32_dwio_write_rap, - reset: pcnet32_dwio_reset + .read_csr = pcnet32_dwio_read_csr, + .write_csr = pcnet32_dwio_write_csr, + .read_bcr = pcnet32_dwio_read_bcr, + .write_bcr = pcnet32_dwio_write_bcr, + .read_rap = pcnet32_dwio_read_rap, + .write_rap = pcnet32_dwio_write_rap, + .reset = pcnet32_dwio_reset }; +static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; + + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + mii_ethtool_gset(&lp->mii_if, cmd); + spin_unlock_irqrestore(&lp->lock, flags); + r = 0; + } + return r; +} + +static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; + + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + r = mii_ethtool_sset(&lp->mii_if, cmd); + spin_unlock_irqrestore(&lp->lock, flags); + } + return r; +} + +static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct pcnet32_private *lp = dev->priv; + + strcpy (info->driver, DRV_NAME); + strcpy (info->version, DRV_VERSION); + if (lp->pci_dev) + strcpy (info->bus_info, pci_name(lp->pci_dev)); + else + sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr); +} + +static u32 pcnet32_get_link(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r; + + spin_lock_irqsave(&lp->lock, flags); + if (lp->mii) { + r = mii_link_ok(&lp->mii_if); + } else { + ulong ioaddr = dev->base_addr; /* card base I/O address */ + r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } + spin_unlock_irqrestore(&lp->lock, flags); + + return r; +} + +static u32 pcnet32_get_msglevel(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + return lp->msg_enable; +} + +static void pcnet32_set_msglevel(struct net_device *dev, u32 value) +{ + struct pcnet32_private *lp = dev->priv; + lp->msg_enable = value; +} + +static int pcnet32_nway_reset(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; + + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + r = mii_nway_restart(&lp->mii_if); + spin_unlock_irqrestore(&lp->lock, flags); + } + return r; +} + +static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + struct pcnet32_private *lp = dev->priv; + + ering->tx_max_pending = TX_RING_SIZE - 1; + ering->tx_pending = lp->cur_tx - lp->dirty_tx; + ering->rx_max_pending = RX_RING_SIZE - 1; + ering->rx_pending = lp->cur_rx & RX_RING_MOD_MASK; +} + +static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test)); +} + +static int pcnet32_self_test_count(struct net_device *dev) +{ + return PCNET32_TEST_LEN; +} + +static void pcnet32_ethtool_test(struct net_device *dev, + struct ethtool_test *test, u64 *data) +{ + struct pcnet32_private *lp = dev->priv; + int rc; + + if (test->flags == ETH_TEST_FL_OFFLINE) { + rc = pcnet32_loopback_test(dev, data); + if (rc) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Loopback test failed.\n", dev->name); + test->flags |= ETH_TEST_FL_FAILED; + } else if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Loopback test passed.\n", dev->name); + } else + printk(KERN_DEBUG "%s: No tests to run (specify 'Offline' on ethtool).", dev->name); +} /* end pcnet32_ethtool_test */ + +static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1) +{ + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; /* access to registers */ + ulong ioaddr = dev->base_addr; /* card base I/O address */ + struct sk_buff *skb; /* sk buff */ + int x, y, i; /* counters */ + int numbuffs = 4; /* number of TX/RX buffers and descs */ + u16 status = 0x8300; /* TX ring status */ + int rc; /* return code */ + int size; /* size of packets */ + unsigned char *packet; /* source packet data */ + static int data_len = 60; /* length of source packets */ + unsigned long flags; + + *data1 = 1; /* status of test, default to fail */ + rc = 1; /* default to fail */ + + spin_lock_irqsave(&lp->lock, flags); + lp->a.write_csr(ioaddr, 0, 0x7904); + + netif_stop_queue(dev); + + /* purge & init rings but don't actually restart */ + pcnet32_restart(dev, 0x0000); + + lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ + + x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */ + x = x | 0x00000002; + a->write_bcr(ioaddr, 32, x); + + /* Initialize Transmit buffers. */ + size = data_len + 15; + for (x=0; xname, __LINE__); + goto clean_up; + } else { + packet = skb->data; + skb_put(skb, size); /* create space for data */ + lp->tx_skbuff[x] = skb; + lp->tx_ring[x].length = le16_to_cpu(-skb->len); + lp->tx_ring[x].misc = 0x00000000; + + /* put DA and SA into the skb */ + for (i=0; i<12; i++) + *packet++ = 0xff; + /* type */ + *packet++ = 0x08; + *packet++ = 0x06; + /* packet number */ + *packet++ = x; + /* fill packet with data */ + for (y=0; ytx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, + skb->len, PCI_DMA_TODEVICE); + lp->tx_ring[x].base = (u32)le32_to_cpu(lp->tx_dma_addr[x]); + wmb(); /* Make sure owner changes after all others are visible */ + lp->tx_ring[x].status = le16_to_cpu(status); + } + } + + lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */ + spin_unlock_irqrestore(&lp->lock, flags); + + mdelay(50); /* wait a bit */ + + spin_lock_irqsave(&lp->lock, flags); + lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ + + if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) { + printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name); + + for (x=0; xname, x); + skb=lp->rx_skbuff[x]; + for (i=0; idata+i)); + } + printk("\n"); + } + } + + x = 0; + rc = 0; + while (xrx_skbuff[x]; + packet = lp->tx_skbuff[x]->data; + for (i=0; idata+i) != packet[i]) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Error in compare! %2x - %02x %02x\n", + dev->name, i, *(skb->data+i), packet[i]); + rc = 1; + break; + } + } + x++; + } + if (!rc) { + *data1 = 0; + } + +clean_up: + x = a->read_csr(ioaddr, 15) & 0xFFFF; + a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */ + + x = a->read_bcr(ioaddr, 32); /* reset internal loopback */ + x = x & ~0x00000002; + a->write_bcr(ioaddr, 32, x); + + pcnet32_restart(dev, 0x0042); /* resume normal operation */ + + netif_wake_queue(dev); + + /* Clear interrupts, and set interrupt enable. */ + lp->a.write_csr(ioaddr, 0, 0x7940); + spin_unlock_irqrestore(&lp->lock, flags); + + return(rc); +} /* end pcnet32_loopback_test */ + +static struct ethtool_ops pcnet32_ethtool_ops = { + .get_settings = pcnet32_get_settings, + .set_settings = pcnet32_set_settings, + .get_drvinfo = pcnet32_get_drvinfo, + .get_msglevel = pcnet32_get_msglevel, + .set_msglevel = pcnet32_set_msglevel, + .nway_reset = pcnet32_nway_reset, + .get_link = pcnet32_get_link, + .get_ringparam = pcnet32_get_ringparam, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_strings = pcnet32_get_strings, + .self_test_count = pcnet32_self_test_count, + .self_test = pcnet32_ethtool_test, +}; + /* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */ @@ -535,10 +824,12 @@ } chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); - if (pcnet32_debug > 2) + if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) + if ((chip_version & 0xfff) != 0x003) { + printk(KERN_INFO PFX "Unsupported chip version.\n"); return -ENODEV; + } /* initialize variables */ fdx = mii = fset = dxsuflo = ltint = 0; @@ -589,7 +880,7 @@ media &= ~3; media |= 1; #endif - if (pcnet32_debug > 2) + if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_DEBUG PFX "media reset to %#x.\n", media); a->write_bcr(ioaddr, 49, media); break; @@ -619,8 +910,10 @@ } dev = alloc_etherdev(0); - if(!dev) + if (!dev) { + printk(KERN_ERR PFX "Memory allocation failed.\n"); return -ENOMEM; + } printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); @@ -693,6 +986,7 @@ /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { + printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); release_region(ioaddr, PCNET32_TOTAL_SIZE); return -ENOMEM; } @@ -707,9 +1001,12 @@ lp->name = chipname; lp->shared_irq = shared; lp->mii_if.full_duplex = fdx; + lp->mii_if.phy_id_mask = 0x1f; + lp->mii_if.reg_num_mask = 0x1f; lp->dxsuflo = dxsuflo; lp->ltint = ltint; lp->mii = mii; + lp->msg_enable = pcnet32_debug; if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else @@ -778,6 +1075,9 @@ } } + /* Set the mii phy_id so that we can query the link state */ + if (lp->mii) + lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -786,11 +1086,16 @@ dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list; dev->do_ioctl = &pcnet32_ioctl; + dev->ethtool_ops = &pcnet32_ethtool_ops; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); - lp->next = pcnet32_dev; - pcnet32_dev = dev; + if (pdev) { + pci_set_drvdata(pdev, dev); + } else { + lp->next = pcnet32_dev; + pcnet32_dev = dev; + } /* Fill in the generic fields of the device structure. */ register_netdev(dev); @@ -807,6 +1112,7 @@ unsigned long ioaddr = dev->base_addr; u16 val; int i; + int rc; if (dev->irq == 0 || request_irq(dev->irq, &pcnet32_interrupt, @@ -815,8 +1121,10 @@ } /* Check for a valid station address */ - if( !is_valid_ether_addr(dev->dev_addr) ) - return -EINVAL; + if (!is_valid_ether_addr(dev->dev_addr)) { + rc = -EINVAL; + goto err_free_irq; + } /* Reset the PCNET32 */ lp->a.reset (ioaddr); @@ -824,7 +1132,7 @@ /* switch pcnet32 to 32bit mode */ lp->a.write_bcr (ioaddr, 20, 2); - if (pcnet32_debug > 1) + if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, tx_ring)), @@ -890,8 +1198,10 @@ lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; - if (pcnet32_init_ring(dev)) - return -ENOMEM; + if (pcnet32_init_ring(dev)) { + rc = -ENOMEM; + goto err_free_ring; + } /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) &0xffff); @@ -912,7 +1222,7 @@ */ lp->a.write_csr (ioaddr, 0, 0x0042); - if (pcnet32_debug > 2) + if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)), lp->a.read_csr(ioaddr, 0)); @@ -921,6 +1231,28 @@ MOD_INC_USE_COUNT; return 0; /* Always succeed */ + +err_free_ring: + /* free any allocated skbuffs */ + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_ring[i].status = 0; + if (lp->rx_skbuff[i]) { + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_skbuff[i]); + } + lp->rx_skbuff[i] = NULL; + lp->rx_dma_addr[i] = 0; + } + /* + * Switch back to 16bit mode to avoid problems with dumb + * DOS packet driver after a warm reboot + */ + lp->a.write_bcr (ioaddr, 20, 4); + +err_free_irq: + free_irq(dev->irq, dev); + return rc; } /* @@ -976,9 +1308,10 @@ } if (lp->rx_dma_addr[i] == 0) - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); + lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, + rx_skbuff->tail, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); - lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); lp->rx_ring[i].status = le16_to_cpu(0x8000); } /* The Tx buffer address is filled in as needed, but we do need to clear @@ -988,6 +1321,7 @@ lp->tx_ring[i].status = 0; lp->tx_dma_addr[i] = 0; } + wmb(); /* Make sure all changes are visible */ lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); for (i = 0; i < 6; i++) @@ -1031,7 +1365,7 @@ dev->name, lp->a.read_csr(ioaddr, 0)); lp->a.write_csr (ioaddr, 0, 0x0004); lp->stats.tx_errors++; - if (pcnet32_debug > 2) { + if (netif_msg_tx_err(lp)) { int i; printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", @@ -1049,7 +1383,7 @@ pcnet32_restart(dev, 0x0042); dev->trans_start = jiffies; - netif_start_queue(dev); + netif_wake_queue(dev); spin_unlock_irqrestore(&lp->lock, flags); } @@ -1064,7 +1398,7 @@ int entry; unsigned long flags; - if (pcnet32_debug > 3) { + if (netif_msg_tx_queued(lp)) { printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, lp->a.read_csr(ioaddr, 0)); } @@ -1075,12 +1409,14 @@ * interrupt when that option is available to us. */ status = 0x8300; + entry = (lp->cur_tx - lp->dirty_tx) & TX_RING_MOD_MASK; if ((lp->ltint) && - ((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) || - (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2))) + ((entry == TX_RING_SIZE/3) || + (entry == (TX_RING_SIZE*2)/3) || + (entry >= TX_RING_SIZE-2))) { /* Enable Successful-TxDone interrupt if we have - * 1/2 of, or nearly all of, our ring buffer Tx'd + * 1/3, 2/3 or nearly all of, our ring buffer Tx'd * but not yet cleaned up. Thus, most of the time, * we will not enable Successful-TxDone interrupts. */ @@ -1092,7 +1428,7 @@ /* Mask to ring buffer boundary. */ entry = lp->cur_tx & TX_RING_MOD_MASK; - /* Caution: the write order is important here, set the base address + /* Caution: the write order is important here, set the status with the "ownership" bits last. */ lp->tx_ring[entry].length = le16_to_cpu(-skb->len); @@ -1113,9 +1449,7 @@ dev->trans_start = jiffies; - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) - netif_start_queue(dev); - else { + if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base != 0) { lp->tx_full = 1; netif_stop_queue(dev); } @@ -1147,12 +1481,15 @@ rap = lp->a.read_rap(ioaddr); while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { + if (csr0 == 0xffff) { + break; /* PCMCIA remove happened */ + } /* Acknowledge all of the current interrupt sources ASAP. */ lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); must_restart = 0; - if (pcnet32_debug > 5) + if (netif_msg_intr(lp)) printk(KERN_DEBUG "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, lp->a.read_csr (ioaddr, 0)); @@ -1161,8 +1498,9 @@ if (csr0 & 0x0200) { /* Tx-done interrupt */ unsigned int dirty_tx = lp->dirty_tx; + int delta; - while (dirty_tx < lp->cur_tx) { + while (dirty_tx != lp->cur_tx) { int entry = dirty_tx & TX_RING_MOD_MASK; int status = (short)le16_to_cpu(lp->tx_ring[entry].status); @@ -1216,15 +1554,17 @@ dirty_tx++; } - if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + delta = (lp->cur_tx - dirty_tx) & (TX_RING_MOD_MASK + TX_RING_SIZE); + if (delta >= TX_RING_SIZE) { printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; + delta -= TX_RING_SIZE; } if (lp->tx_full && netif_queue_stopped(dev) && - dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + delta < TX_RING_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); @@ -1264,7 +1604,7 @@ lp->a.write_csr (ioaddr, 0, 0x7940); lp->a.write_rap (ioaddr,rap); - if (pcnet32_debug > 4) + if (netif_msg_intr(lp)) printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n", dev->name, lp->a.read_csr (ioaddr, 0)); @@ -1312,13 +1652,14 @@ if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { skb_reserve (newskb, 2); skb = lp->rx_skbuff[entry]; - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], skb->len, PCI_DMA_FROMDEVICE); + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], + PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); skb_put (skb, pkt_len); lp->rx_skbuff[entry] = newskb; newskb->dev = dev; lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, - newskb->len, PCI_DMA_FROMDEVICE); + PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; } else @@ -1347,7 +1688,7 @@ skb_put(skb,pkt_len); /* Make room */ pci_dma_sync_single(lp->pci_dev, lp->rx_dma_addr[entry], - PKT_BUF_SZ, + PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, (unsigned char *)(lp->rx_skbuff[entry]->tail), @@ -1364,7 +1705,8 @@ * The docs say that the buffer length isn't touched, but Andrew Boyd * of QNX reports that some revs of the 79C965 clear it. */ - lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ); + wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[entry].status |= le16_to_cpu(0x8000); entry = (++lp->cur_rx) & RX_RING_MOD_MASK; } @@ -1383,7 +1725,7 @@ lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); - if (pcnet32_debug > 1) + if (netif_msg_ifdown(lp)) printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, lp->a.read_csr (ioaddr, 0)); @@ -1402,7 +1744,8 @@ for (i = 0; i < RX_RING_SIZE; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE); + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; @@ -1472,7 +1815,9 @@ crc = ether_crc_le(6, addrs); crc = crc >> 26; - mcast_table [crc >> 4] |= cpu_to_le16(1 << (crc & 0xf)); + mcast_table [crc >> 4] = le16_to_cpu( + le16_to_cpu(mcast_table [crc >> 4]) | (1 << (crc & 0xf)) + ); } return; } @@ -1537,136 +1882,49 @@ lp->a.write_bcr(ioaddr, 33, phyaddr); } -static int pcnet32_ethtool_ioctl (struct net_device *dev, void *useraddr) +static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct pcnet32_private *lp = dev->priv; - u32 ethcmd; - int phyaddr = 0; - int phy_id = 0; - unsigned long ioaddr = dev->base_addr; - - if (lp->mii) { - phyaddr = lp->a.read_bcr (ioaddr, 33); - phy_id = (phyaddr >> 5) & 0x1f; - lp->mii_if.phy_id = phy_id; - } - - if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) - return -EFAULT; - - switch (ethcmd) { - case ETHTOOL_GDRVINFO: { - struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; - strcpy (info.driver, DRV_NAME); - strcpy (info.version, DRV_VERSION); - if (lp->pci_dev) - strcpy (info.bus_info, lp->pci_dev->slot_name); - else - sprintf(info.bus_info, "VLB 0x%lx", dev->base_addr); - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } - - /* get settings */ - case ETHTOOL_GSET: { - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; - spin_lock_irq(&lp->lock); - mii_ethtool_gset(&lp->mii_if, &ecmd); - spin_unlock_irq(&lp->lock); - if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) - return -EFAULT; - return 0; - } - /* set settings */ - case ETHTOOL_SSET: { - int r; - struct ethtool_cmd ecmd; - if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) - return -EFAULT; - spin_lock_irq(&lp->lock); - r = mii_ethtool_sset(&lp->mii_if, &ecmd); - spin_unlock_irq(&lp->lock); - return r; - } - /* restart autonegotiation */ - case ETHTOOL_NWAY_RST: { - return mii_nway_restart(&lp->mii_if); - } - /* get link status */ - case ETHTOOL_GLINK: { - struct ethtool_value edata = {ETHTOOL_GLINK}; - edata.data = mii_link_ok(&lp->mii_if); - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } + struct pcnet32_private *lp = dev->priv; + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; + int rc; + unsigned long flags; - /* get message-level */ - case ETHTOOL_GMSGLVL: { - struct ethtool_value edata = {ETHTOOL_GMSGLVL}; - edata.data = pcnet32_debug; - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; - } - /* set message-level */ - case ETHTOOL_SMSGLVL: { - struct ethtool_value edata; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - pcnet32_debug = edata.data; - return 0; - } - default: - break; - } + /* SIOC[GS]MIIxxx ioctls */ + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); + spin_unlock_irqrestore(&lp->lock, flags); + } else { + rc = -EOPNOTSUPP; + } - return -EOPNOTSUPP; + return rc; } -static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static void __devexit pcnet32_remove_one(struct pci_dev *pdev) { - unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = dev->priv; - struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; - int phyaddr = lp->a.read_bcr (ioaddr, 33); + struct net_device *dev = pci_get_drvdata(pdev); - if (cmd == SIOCETHTOOL) - return pcnet32_ethtool_ioctl(dev, (void *) rq->ifr_data); + if (dev) { + struct pcnet32_private *lp = dev->priv; - if (lp->mii) { - switch(cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - data->phy_id = (phyaddr >> 5) & 0x1f; - /* Fall Through */ - case SIOCGMIIREG: /* Read MII PHY register. */ - lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); - data->val_out = lp->a.read_bcr (ioaddr, 34); - lp->a.write_bcr (ioaddr, 33, phyaddr); - return 0; - case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - lp->a.write_bcr (ioaddr, 33, ((data->phy_id & 0x1f) << 5) | (data->reg_num & 0x1f)); - lp->a.write_bcr (ioaddr, 34, data->val_in); - lp->a.write_bcr (ioaddr, 33, phyaddr); - return 0; - default: - return -EOPNOTSUPP; - } + unregister_netdev(dev); + release_region(dev->base_addr, PCNET32_TOTAL_SIZE); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + free_netdev(dev); + pci_set_drvdata(pdev, NULL); } - return -EOPNOTSUPP; } static struct pci_driver pcnet32_driver = { - name: DRV_NAME, - probe: pcnet32_probe_pci, - id_table: pcnet32_pci_tbl, + .name = DRV_NAME, + .probe = pcnet32_probe_pci, + .remove = __devexit_p(pcnet32_remove_one), + .id_table = pcnet32_pci_tbl, }; MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)"); +MODULE_PARM_DESC(debug, DRV_NAME " debug level"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt"); MODULE_PARM(rx_copybreak, "i"); @@ -1687,19 +1945,21 @@ /* An additional parameter that may be passed in... */ static int debug = -1; static int tx_start_pt = -1; +static int pcnet32_have_pci; static int __init pcnet32_init_module(void) { printk(KERN_INFO "%s", version); - if (debug > 0) - pcnet32_debug = debug; + if (debug >= 0 && debug < (sizeof(int) - 1)) + pcnet32_debug = 1 << debug; if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) tx_start = tx_start_pt; /* find the PCI devices */ - pci_module_init(&pcnet32_driver); + if (!pci_module_init(&pcnet32_driver)) + pcnet32_have_pci = 1; /* should we find any remaining VLbus devices ? */ if (pcnet32vlb) @@ -1708,7 +1968,7 @@ if (cards_found) printk(KERN_INFO PFX "%d cards_found.\n", cards_found); - return cards_found ? 0 : -ENODEV; + return (pcnet32_have_pci + cards_found) ? 0 : -ENODEV; } static void __exit pcnet32_cleanup_module(void) @@ -1721,12 +1981,12 @@ next_dev = lp->next; unregister_netdev(pcnet32_dev); release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - if (lp->pci_dev) - pci_unregister_driver(&pcnet32_driver); pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - kfree(pcnet32_dev); + free_netdev(pcnet32_dev); pcnet32_dev = next_dev; } + if (pcnet32_have_pci) + pci_unregister_driver(&pcnet32_driver); } module_init(pcnet32_init_module); diff -urN linux-2.4.25/drivers/net/r8169.c linux-2.4.26/drivers/net/r8169.c --- linux-2.4.25/drivers/net/r8169.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/r8169.c 2004-04-14 06:05:30.000000000 -0700 @@ -874,7 +874,6 @@ void *ioaddr) { unsigned long dirty_tx, tx_left = 0; - int entry = tp->cur_tx % NUM_TX_DESC; assert(dev != NULL); assert(tp != NULL); @@ -884,14 +883,18 @@ tx_left = tp->cur_tx - dirty_tx; while (tx_left > 0) { + int entry = dirty_tx % NUM_TX_DESC; + if ((tp->TxDescArray[entry].status & OWNbit) == 0) { - dev_kfree_skb_irq(tp-> - Tx_skbuff[dirty_tx % NUM_TX_DESC]); - tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL; + struct sk_buff *skb = tp->Tx_skbuff[entry]; + + tp->stats.tx_bytes += skb->len >= ETH_ZLEN ? + skb->len : ETH_ZLEN; tp->stats.tx_packets++; + dev_kfree_skb_irq(skb); + tp->Tx_skbuff[entry] = NULL; dirty_tx++; tx_left--; - entry++; } } diff -urN linux-2.4.25/drivers/net/sis900.c linux-2.4.26/drivers/net/sis900.c --- linux-2.4.25/drivers/net/sis900.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sis900.c 2004-04-14 06:05:30.000000000 -0700 @@ -2095,7 +2095,7 @@ i++, mclist = mclist->next) { unsigned int bit_nr = sis900_mcast_bitnr(mclist->dmi_addr, revision); - mc_filter[bit_nr >> 4] |= (1 << bit_nr); + mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf)); } } diff -urN linux-2.4.25/drivers/net/sk98lin/h/lm80.h linux-2.4.26/drivers/net/sk98lin/h/lm80.h --- linux-2.4.25/drivers/net/sk98lin/h/lm80.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/lm80.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: lm80.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.6 $ - * Date: $Date: 2003/05/13 17:26:52 $ * Purpose: Contains all defines for the LM80 Chip * (National Semiconductor). * @@ -23,32 +21,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: lm80.h,v $ - * Revision 1.6 2003/05/13 17:26:52 mkarl - * Editorial changes. - * - * Revision 1.5 2003/03/31 07:15:18 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.4 2002/04/25 11:04:10 rschmidt - * Editorial changes - * - * Revision 1.3 1999/11/22 13:41:19 cgoos - * Changed license header to GPL. - * - * Revision 1.2 1999/03/12 13:26:51 malthoff - * remove __STDC__. - * - * Revision 1.1 1998/06/19 09:28:31 malthoff - * created. - * - * - ******************************************************************************/ - #ifndef __INC_LM80_H #define __INC_LM80_H diff -urN linux-2.4.25/drivers/net/sk98lin/h/skaddr.h linux-2.4.26/drivers/net/sk98lin/h/skaddr.h --- linux-2.4.25/drivers/net/sk98lin/h/skaddr.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skaddr.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skaddr.h * Project: Gigabit Ethernet Adapters, ADDR-Modul - * Version: $Revision: 1.29 $ - * Date: $Date: 2003/05/13 16:57:24 $ * Purpose: Header file for Address Management (MC, UC, Prom). * ******************************************************************************/ @@ -24,112 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skaddr.h,v $ - * Revision 1.29 2003/05/13 16:57:24 mkarl - * Changes for SLIM driver. - * Editorial changes. - * - * Revision 1.28 2003/04/15 09:33:22 tschilli - * Copyright messages changed. - * - * Revision 1.27 2003/04/14 15:55:11 tschilli - * "#error C++ is not yet supported." removed. - * - * Revision 1.26 2002/11/15 07:24:42 tschilli - * SK_ADDR_EQUAL macro fixed. - * - * Revision 1.25 2002/06/10 13:55:18 tschilli - * Changes for handling YUKON. - * All changes are internally and not visible to the programmer - * using this module. - * - * Revision 1.24 2001/01/22 13:41:34 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.23 2000/08/10 11:27:50 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * - * Revision 1.22 2000/08/07 11:10:40 rassmann - * Editorial changes. - * - * Revision 1.21 2000/05/04 09:39:59 rassmann - * Editorial changes. - * Corrected multicast address hashing. - * - * Revision 1.20 1999/11/22 13:46:14 cgoos - * Changed license header to GPL. - * Allowing overwrite for SK_ADDR_EQUAL. - * - * Revision 1.19 1999/05/28 10:56:07 rassmann - * Editorial changes. - * - * Revision 1.18 1999/04/06 17:22:04 rassmann - * Added private "ActivePort". - * - * Revision 1.17 1999/01/14 16:18:19 rassmann - * Corrected multicast initialization. - * - * Revision 1.16 1999/01/04 10:30:36 rassmann - * SkAddrOverride only possible after SK_INIT_IO phase. - * - * Revision 1.15 1998/12/29 13:13:11 rassmann - * An address override is now preserved in the SK_INIT_IO phase. - * All functions return an int now. - * Extended parameter checking. - * - * Revision 1.14 1998/11/24 12:39:45 rassmann - * Reserved multicast entry for BPDU address. - * 13 multicast entries left for protocol. - * - * Revision 1.13 1998/11/13 17:24:32 rassmann - * Changed return value of SkAddrOverride to int. - * - * Revision 1.12 1998/11/13 16:56:19 rassmann - * Added macro SK_ADDR_COMPARE. - * Changed return type of SkAddrOverride to SK_BOOL. - * - * Revision 1.11 1998/10/28 18:16:35 rassmann - * Avoiding I/Os before SK_INIT_RUN level. - * Aligning InexactFilter. - * - * Revision 1.10 1998/10/22 11:39:10 rassmann - * Corrected signed/unsigned mismatches. - * - * Revision 1.9 1998/10/15 15:15:49 rassmann - * Changed Flags Parameters from SK_U8 to int. - * Checked with lint. - * - * Revision 1.8 1998/09/24 19:15:12 rassmann - * Code cleanup. - * - * Revision 1.7 1998/09/18 20:22:13 rassmann - * Added HW access. - * - * Revision 1.6 1998/09/04 19:40:20 rassmann - * Interface enhancements. - * - * Revision 1.5 1998/09/04 12:40:57 rassmann - * Interface cleanup. - * - * Revision 1.4 1998/09/04 12:14:13 rassmann - * Interface cleanup. - * - * Revision 1.3 1998/09/02 16:56:40 rassmann - * Updated interface. - * - * Revision 1.2 1998/08/27 14:26:09 rassmann - * Updated interface. - * - * Revision 1.1 1998/08/21 08:31:08 rassmann - * First public version. - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This module is intended to manage multicast addresses and promiscuous mode diff -urN linux-2.4.25/drivers/net/sk98lin/h/skcsum.h linux-2.4.26/drivers/net/sk98lin/h/skcsum.h --- linux-2.4.25/drivers/net/sk98lin/h/skcsum.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skcsum.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skcsum.h * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) - * Version: $Revision: 1.10 $ - * Date: $Date: 2003/08/20 13:59:57 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -23,52 +21,6 @@ /****************************************************************************** * - * History: - * - * $Log: skcsum.h,v $ - * Revision 1.10 2003/08/20 13:59:57 mschmid - * Changed notation of #ifndef SkCsCalculateChecksum to - * #ifndef SK_CS_CALCULATE_CHECKSUM - * - * Revision 1.9 2001/02/06 11:21:39 rassmann - * Editorial changes. - * - * Revision 1.8 2001/02/06 11:15:36 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.7 2000/06/29 13:17:05 rassmann - * Corrected reception of a packet with UDP checksum == 0 (which means there - * is no UDP checksum). - * - * Revision 1.6 2000/02/28 12:33:44 cgoos - * Changed C++ style comments to C style. - * - * Revision 1.5 2000/02/21 12:10:05 cgoos - * Fixed license comment. - * - * Revision 1.4 2000/02/21 11:08:37 cgoos - * Merged changes back into common source. - * - * Revision 1.1 1999/07/26 14:47:49 mkarl - * changed from common source to windows specific source - * added return SKCS_STATUS_IP_CSUM_ERROR_UDP and - * SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester - * changes for Tx csum offload - * - * Revision 1.2 1998/09/04 12:16:34 mhaveman - * Checked in for Stephan to allow compilation. - * -Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic - * -Added prototype for SkCsEvent() - * - * Revision 1.1 1998/09/01 15:36:53 swolf - * initial revision - * - * 01-Sep-1998 sw Created. - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * Public header file for the "GEnesis" common module "CSUM". diff -urN linux-2.4.25/drivers/net/sk98lin/h/skdebug.h linux-2.4.26/drivers/net/sk98lin/h/skdebug.h --- linux-2.4.25/drivers/net/sk98lin/h/skdebug.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skdebug.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skdebug.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.14 $ - * Date: $Date: 2003/05/13 17:26:00 $ * Purpose: SK specific DEBUG support * ******************************************************************************/ @@ -22,58 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: skdebug.h,v $ - * Revision 1.14 2003/05/13 17:26:00 mkarl - * Editorial changes. - * - * Revision 1.13 2003/03/31 07:16:39 mkarl - * Corrected Copyright. - * - * Revision 1.12 2002/07/15 15:37:13 rschmidt - * Power Management support - * Editorial changes - * - * Revision 1.11 2002/04/25 11:04:39 rschmidt - * Editorial changes - * - * Revision 1.10 1999/11/22 13:47:40 cgoos - * Changed license header to GPL. - * - * Revision 1.9 1999/09/14 14:02:43 rwahl - * Added SK_DBGMOD_PECP. - * - * Revision 1.8 1998/11/25 08:31:54 gklug - * fix: no C++ comments allowed in common sources - * - * Revision 1.7 1998/11/24 16:47:24 swolf - * Driver may now define its own SK_DBG_MSG() (eg. in "h/skdrv1st.h"). - * - * Revision 1.6 1998/10/28 10:23:55 rassmann - * ADDED SK_DBGMOD_ADDR. - * - * Revision 1.5 1998/10/22 09:43:55 gklug - * add: CSUM module - * - * Revision 1.4 1998/10/01 07:54:44 gklug - * add: PNMI debug module - * - * Revision 1.3 1998/09/18 08:32:34 afischer - * Macros changed according ssr-spec.: - * SK_DBG_MODCHK -> SK_DBG_CHKMOD - * SK_DBG_CATCHK -> SK_DBG_CHKCAT - * - * Revision 1.2 1998/07/03 14:38:25 malthoff - * Add category SK_DBGCAT_FATAL. - * - * Revision 1.1 1998/06/19 13:39:01 malthoff - * created. - * - * - ******************************************************************************/ - #ifndef __INC_SKDEBUG_H #define __INC_SKDEBUG_H diff -urN linux-2.4.25/drivers/net/sk98lin/h/skdrv1st.h linux-2.4.26/drivers/net/sk98lin/h/skdrv1st.h --- linux-2.4.25/drivers/net/sk98lin/h/skdrv1st.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skdrv1st.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.4 $ - * Date: $Date: 2003/11/12 14:28:14 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ @@ -24,87 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skdrv1st.h,v $ - * Revision 1.4 2003/11/12 14:28:14 rroesler - * Fix: use dedicated ip_fast_csum() on X86_64 systems - * - * Revision 1.3 2003/10/07 08:16:52 mlindner - * Fix: Copyright changes - * - * Revision 1.2 2003/09/29 12:05:59 mlindner - * Fix: Added define SK_CS_CALCULSTE_CHECKSUM - * - * Revision 1.1 2003/07/21 07:22:43 rroesler - * Fix: Re-Enter after CVS crash - * - * Revision 1.15 2003/07/17 14:54:09 rroesler - * Fix: Corrected SK_PNMI_READ macros to copy right amount of bytes - * - * Revision 1.14 2003/06/03 14:36:32 mlindner - * Add: Additions for SK_SLIM - * - * Revision 1.13 2003/05/26 14:03:06 mlindner - * Add: Support for SLIM skaddr - * - * Revision 1.12 2003/05/26 12:56:39 mlindner - * Add: Support for Kernel 2.5/2.6 - * Add: New SkOsGetTimeCurrent function - * Add: SK_PNMI_HUNDREDS_SEC definition - * Fix: SK_TICKS_PER_SEC on Intel Itanium2 - * - * Revision 1.11 2003/02/25 14:16:40 mlindner - * Fix: Copyright statement - * - * Revision 1.10 2002/10/02 12:46:02 mlindner - * Add: Support for Yukon - * - * Revision 1.9.2.2 2001/12/07 12:06:42 mlindner - * Fix: malloc -> slab changes - * - * Revision 1.9.2.1 2001/03/12 16:50:59 mlindner - * chg: kernel 2.4 adaption - * - * Revision 1.9 2001/01/22 14:16:04 mlindner - * added ProcFs functionality - * Dual Net functionality integrated - * Rlmt networks added - * - * Revision 1.8 2000/02/21 12:19:18 cgoos - * Added default for SK_DEBUG_CHKMOD/_CHKCAT - * - * Revision 1.7 1999/11/22 13:50:00 cgoos - * Changed license header to GPL. - * Added overwrite for several functions. - * Removed linux 2.0.x definitions. - * Removed PCI vendor ID definition (now in kernel). - * - * Revision 1.6 1999/07/27 08:03:33 cgoos - * Changed SK_IN/OUT macros to readX/writeX instead of memory - * accesses (necessary for ALPHA). - * - * Revision 1.5 1999/07/23 12:10:21 cgoos - * Removed SK_RLMT_SLOW_LOOKAHEAD define. - * - * Revision 1.4 1999/07/14 12:31:13 cgoos - * Added SK_RLMT_SLOW_LOOKAHEAD define. - * - * Revision 1.3 1999/04/07 10:12:54 cgoos - * Added check for KERNEL and OPTIMIZATION defines. - * - * Revision 1.2 1999/03/01 08:51:47 cgoos - * Fixed pcibios_read/write definitions. - * - * Revision 1.1 1999/02/16 07:40:49 cgoos - * First version. - * - * - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This is the first include file of the driver, which includes all diff -urN linux-2.4.25/drivers/net/sk98lin/h/skdrv2nd.h linux-2.4.26/drivers/net/sk98lin/h/skdrv2nd.h --- linux-2.4.25/drivers/net/sk98lin/h/skdrv2nd.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skdrv2nd.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skdrv2nd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.10 $ - * Date: $Date: 2003/12/11 16:04:45 $ * Purpose: Second header file for driver and all other modules * ******************************************************************************/ @@ -24,122 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skdrv2nd.h,v $ - * Revision 1.10 2003/12/11 16:04:45 mlindner - * Add: New pnmi data backup structure - * - * Revision 1.9 2003/11/10 09:31:37 rroesler - * Add: pnmiBackup structure for DIAG backup restore - * - * Revision 1.8 2003/10/22 14:18:32 rroesler - * Fix: DIAG handling for DualNet cards - * - * Revision 1.7 2003/10/07 09:34:59 mlindner - * Add: New defines for lower and upper range values (interrupt moderation) - * - * Revision 1.6 2003/10/07 08:16:51 mlindner - * Fix: Copyright changes - * - * Revision 1.5 2003/09/01 13:10:39 rroesler - * Add: Prototypes for DIAG Attach/Detach functions - * - * Revision 1.4 2003/09/01 12:33:38 rroesler - * Add: Defines for optimized DIAG interaction - * - * Revision 1.3 2003/08/12 16:51:18 mlindner - * Fix: UDP and TCP Proto checks - * Fix: UDP header offset - * - * Revision 1.2 2003/08/07 10:50:54 mlindner - * Add: Speed and HW-Csum support for Yukon Lite chipset - * - * Revision 1.1 2003/07/21 07:25:29 rroesler - * Fix: Re-Enter after CVS crash - * - * Revision 1.19 2003/07/07 09:53:10 rroesler - * Fix: Removed proprietary RxTx defines and used the ones from skgehw.h instead - * - * Revision 1.18 2003/06/12 07:54:14 mlindner - * Fix: Changed Descriptor Alignment to 64 Byte - * - * Revision 1.17 2003/05/26 12:56:39 mlindner - * Add: Support for Kernel 2.5/2.6 - * Add: New SkOsGetTimeCurrent function - * Add: SK_PNMI_HUNDREDS_SEC definition - * Fix: SK_TICKS_PER_SEC on Intel Itanium2 - * - * Revision 1.16 2003/03/21 14:56:18 rroesler - * Added code regarding interrupt moderation - * - * Revision 1.15 2003/02/25 14:16:40 mlindner - * Fix: Copyright statement - * - * Revision 1.14 2003/02/25 13:26:26 mlindner - * Add: Support for various vendors - * - * Revision 1.13 2002/10/02 12:46:02 mlindner - * Add: Support for Yukon - * - * Revision 1.12.2.2 2001/09/05 12:14:50 mlindner - * add: New hardware revision int - * - * Revision 1.12.2.1 2001/03/12 16:50:59 mlindner - * chg: kernel 2.4 adaption - * - * Revision 1.12 2001/03/01 12:52:15 mlindner - * Fixed ring size - * - * Revision 1.11 2001/02/19 13:28:02 mlindner - * Changed PNMI parameter values - * - * Revision 1.10 2001/01/22 14:16:04 mlindner - * added ProcFs functionality - * Dual Net functionality integrated - * Rlmt networks added - * - * Revision 1.1 2000/10/05 19:46:50 phargrov - * Add directory src/vipk_devs_nonlbl/vipk_sk98lin/ - * This is the SysKonnect SK-98xx Gigabit Ethernet driver, - * contributed by SysKonnect. - * - * Revision 1.9 2000/02/21 10:39:55 cgoos - * Added flag for jumbo support usage. - * - * Revision 1.8 1999/11/22 13:50:44 cgoos - * Changed license header to GPL. - * Fixed two comments. - * - * Revision 1.7 1999/09/28 12:38:21 cgoos - * Added CheckQueue to SK_AC. - * - * Revision 1.6 1999/07/27 08:04:05 cgoos - * Added checksumming variables to SK_AC. - * - * Revision 1.5 1999/03/29 12:33:26 cgoos - * Rreversed to fine lock granularity. - * - * Revision 1.4 1999/03/15 12:14:02 cgoos - * Added DriverLock to SK_AC. - * Removed other locks. - * - * Revision 1.3 1999/03/01 08:52:27 cgoos - * Changed pAC->PciDev declaration. - * - * Revision 1.2 1999/02/18 10:57:14 cgoos - * Removed SkDrvTimeStamp prototype. - * Fixed SkGeOsGetTime prototype. - * - * Revision 1.1 1999/02/16 07:41:01 cgoos - * First version. - * - * - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This is the second include file of the driver, which includes all other diff -urN linux-2.4.25/drivers/net/sk98lin/h/skerror.h linux-2.4.26/drivers/net/sk98lin/h/skerror.h --- linux-2.4.25/drivers/net/sk98lin/h/skerror.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skerror.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skerror.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.7 $ - * Date: $Date: 2003/05/13 17:25:13 $ * Purpose: SK specific Error log support * ******************************************************************************/ @@ -22,38 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: skerror.h,v $ - * Revision 1.7 2003/05/13 17:25:13 mkarl - * Editorial changes. - * - * Revision 1.6 2003/03/31 07:17:48 mkarl - * Corrected Copyright. - * - * Revision 1.5 2002/04/25 11:05:10 rschmidt - * Editorial changes - * - * Revision 1.4 1999/11/22 13:51:59 cgoos - * Changed license header to GPL. - * - * Revision 1.3 1999/09/14 14:04:42 rwahl - * Added error base SK_ERRBASE_PECP. - * Changed error base for driver. - * - * Revision 1.2 1998/08/11 11:15:41 gklug - * chg: comments - * - * Revision 1.1 1998/08/11 11:09:38 gklug - * add: error bases - * add: error Classes - * first version - * - * - * - ******************************************************************************/ - #ifndef _INC_SKERROR_H_ #define _INC_SKERROR_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgedrv.h linux-2.4.26/drivers/net/sk98lin/h/skgedrv.h --- linux-2.4.25/drivers/net/sk98lin/h/skgedrv.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgedrv.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgedrv.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.10 $ - * Date: $Date: 2003/07/04 12:25:01 $ * Purpose: Interface with the driver * ******************************************************************************/ @@ -22,47 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgedrv.h,v $ - * Revision 1.10 2003/07/04 12:25:01 rschmidt - * Added event SK_DRV_DOWNSHIFT_DET for Downshift 4-Pair / 2-Pair - * - * Revision 1.9 2003/05/13 17:24:21 mkarl - * Added events SK_DRV_LINK_UP and SK_DRV_LINK_DOWN for drivers not using - * RLMT (SK_NO_RLMT). - * Editorial changes. - * - * Revision 1.8 2003/03/31 07:18:54 mkarl - * Corrected Copyright. - * - * Revision 1.7 2003/03/18 09:43:47 rroesler - * Added new event for timer - * - * Revision 1.6 2002/07/15 15:38:01 rschmidt - * Power Management support - * Editorial changes - * - * Revision 1.5 2002/04/25 11:05:47 rschmidt - * Editorial changes - * - * Revision 1.4 1999/11/22 13:52:46 cgoos - * Changed license header to GPL. - * - * Revision 1.3 1998/12/01 13:31:39 cgoos - * SWITCH INTERN Event added. - * - * Revision 1.2 1998/11/25 08:28:38 gklug - * rmv: PORT SWITCH Event - * - * Revision 1.1 1998/09/29 06:14:07 gklug - * add: driver events (initial version) - * - * - ******************************************************************************/ - #ifndef __INC_SKGEDRV_H_ #define __INC_SKGEDRV_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgehw.h linux-2.4.26/drivers/net/sk98lin/h/skgehw.h --- linux-2.4.25/drivers/net/sk98lin/h/skgehw.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgehw.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgehw.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.56 $ - * Date: $Date: 2003/09/23 09:01:00 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product Family * ******************************************************************************/ @@ -22,236 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: skgehw.h,v $ - * Revision 1.56 2003/09/23 09:01:00 malthoff - * Minor change: Define I2C device size constants as long. - * - * Revision 1.55 2003/09/16 14:03:34 rschmidt - * Added define for YUKON-Lite Rev. A1,A2 Chip Revision - * Moved defines for PHY power down modes to skgeinit.h - * Editorial changes - * - * Revision 1.54 2003/09/16 07:37:58 mschmid - * Added defines for Marvell PHY low power modes - * - * Revision 1.53 2003/07/04 12:39:01 rschmidt - * Added SK_FAR to pointers in XM_IN32() and GM_IN32() macros (for PXE) - * Editorial changes - * - * Revision 1.52 2003/05/13 17:16:36 mkarl - * Added SK_FAR for PXE. - * Editorial changes. - * - * Revision 1.51 2003/04/08 16:31:50 rschmidt - * Added defines for new Chip IDs (YUKON-Lite, YUKON-LP) - * Editorial changes - * - * Revision 1.50 2003/03/31 07:29:45 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.49 2003/01/28 09:43:49 rschmidt - * Added defines for PCI-Spec. 2.3 IRQ - * Added defines for CLK_RUN (YUKON-Lite) - * Editorial changes - * - * Revision 1.48 2002/12/05 10:25:11 rschmidt - * Added defines for Half Duplex Burst Mode On/Off - * Added defines for Rx GMAC FIFO Flush feature - * Editorial changes - * - * Revision 1.47 2002/11/12 17:01:31 rschmidt - * Added defines for WOL_CTL_DEFAULT - * Editorial changes - * - * Revision 1.46 2002/10/14 14:47:57 rschmidt - * Corrected bit mask for HW self test results - * Added defines for WOL Registers - * Editorial changes - * - * Revision 1.45 2002/10/11 09:25:22 mkarl - * Added bit mask for HW self test results. - * - * Revision 1.44 2002/08/16 14:44:36 rschmidt - * Added define GPC_HWCFG_GMII_FIB for YUKON Fiber - * - * Revision 1.43 2002/08/12 13:31:50 rschmidt - * Corrected macros for GMAC Address Registers: GM_INADDR(), - * GM_OUTADDR(), GM_INHASH, GM_OUTHASH. - * Editorial changes - * - * Revision 1.42 2002/08/08 15:37:56 rschmidt - * Added defines for Power Management Capabilities - * Editorial changes - * - * Revision 1.41 2002/07/23 16:02:25 rschmidt - * Added macro WOL_REG() to access WOL reg. (HW-Bug in YUKON 1st rev.) - * - * Revision 1.40 2002/07/15 15:41:37 rschmidt - * Added new defines for Power Management Cap. & Control - * Editorial changes - * - * Revision 1.39 2002/06/10 09:37:07 rschmidt - * Added macros for the ADDR-Module - * - * Revision 1.38 2002/06/05 08:15:19 rschmidt - * Added defines for WOL Registers - * Editorial changes - * - * Revision 1.37 2002/04/25 11:39:23 rschmidt - * Added new defines for PCI Our Register 1 - * Added new registers and defines for YUKON (Rx FIFO, Tx FIFO, - * Time Stamp Timer, GMAC Control, GPHY Control,Link Control, - * GMAC IRQ Source and Mask, Wake-up Frame Pattern Match); - * Added new defines for Control/Status (VAUX available) - * Added Chip ID for YUKON - * Added define for descriptors with UDP ext. for YUKON - * Added macros to access the GMAC - * Added new Phy Type for Marvell 88E1011S (GPHY) - * Editorial changes - * - * Revision 1.36 2000/11/09 12:32:49 rassmann - * Renamed variables. - * - * Revision 1.35 2000/05/19 10:17:13 cgoos - * Added inactivity check in PHY_READ (in DEBUG mode only). - * - * Revision 1.34 1999/11/22 13:53:40 cgoos - * Changed license header to GPL. - * - * Revision 1.33 1999/08/27 11:17:10 malthoff - * It's more savely to put brackets around macro parameters. - * Brackets added for PHY_READ and PHY_WRITE. - * - * Revision 1.32 1999/05/19 07:31:01 cgoos - * Changes for 1000Base-T. - * Added HWAC_LINK_LED macro. - * - * Revision 1.31 1999/03/12 13:27:40 malthoff - * Remove __STDC__. - * - * Revision 1.30 1999/02/09 09:28:20 malthoff - * Add PCI_ERRBITS. - * - * Revision 1.29 1999/01/26 08:55:48 malthoff - * Bugfix: The 16 bit field relations inside the descriptor are - * endianess dependend if the descriptor reversal feature - * (PCI_REV_DESC bit in PCI_OUR_REG_2) is enabled. - * Drivers which use this feature has to set the define - * SK_USE_REV_DESC. - * - * Revision 1.28 1998/12/10 11:10:22 malthoff - * bug fix: IS_IRQ_STAT and IS_IRQ_MST_ERR has been twisted. - * - * Revision 1.27 1998/11/13 14:19:21 malthoff - * Bug Fix: The bit definition of B3_PA_CTRL has completely - * changed from HW Spec v1.3 to v1.5. - * - * Revision 1.26 1998/11/04 08:31:48 cgoos - * Fixed byte ordering in XM_OUTADDR/XM_OUTHASH macros. - * - * Revision 1.25 1998/11/04 07:16:25 cgoos - * Changed byte ordering in XM_INADDR/XM_INHASH again. - * - * Revision 1.24 1998/11/02 11:08:43 malthoff - * RxCtrl and TxCtrl must be volatile. - * - * Revision 1.23 1998/10/28 13:50:45 malthoff - * Fix: Endian support missing in XM_IN/OUT-ADDR/HASH macros. - * - * Revision 1.22 1998/10/26 08:01:36 malthoff - * RX_MFF_CTRL1 is split up into RX_MFF_CTRL1, - * RX_MFF_STAT_TO, and RX_MFF_TIST_TO. - * TX_MFF_CTRL1 is split up TX_MFF_CTRL1 and TX_MFF_WAF. - * - * Revision 1.21 1998/10/20 07:43:10 malthoff - * Fix: XM_IN/OUT/ADDR/HASH macros: - * The pointer must be casted. - * - * Revision 1.20 1998/10/19 15:53:59 malthoff - * Remove ML proto definitions. - * - * Revision 1.19 1998/10/16 14:40:17 gklug - * fix: typo B0_XM_IMSK regs - * - * Revision 1.18 1998/10/16 09:46:54 malthoff - * Remove temp defines for ML diag prototype. - * Fix register definition for B0_XM1_PHY_DATA, B0_XM1_PHY_DATA - * B0_XM2_PHY_DATA, B0_XM2_PHY_ADDR, B0_XA1_CSR, B0_XS1_CSR, - * B0_XS2_CSR, and B0_XA2_CSR. - * - * Revision 1.17 1998/10/14 06:03:14 cgoos - * Changed shifted constant to ULONG. - * - * Revision 1.16 1998/10/09 07:05:41 malthoff - * Rename ALL_PA_ENA_TO to PA_ENA_TO_ALL. - * - * Revision 1.15 1998/10/05 07:54:23 malthoff - * Split up RB_CTRL and it's bit definition into - * RB_CTRL, RB_TST1, and RB_TST2. - * Rename RB_RX_HTPP to RB_RX_LTPP. - * Add ALL_PA_ENA_TO. Modify F_WATER_MARK - * according to HW Spec. v1.5. - * Add MFF_TX_CTRL_DEF. - * - * Revision 1.14 1998/09/28 13:31:16 malthoff - * bug fix: B2_MAC_3 is 0x110 not 0x114 - * - * Revision 1.13 1998/09/24 14:42:56 malthoff - * Split the RX_MFF_TST into RX_MFF_CTRL2, - * RX_MFF_TST1, and RX_MFF_TST2. - * Rename RX_MFF_CTRL to RX_MFF_CTRL1. - * Add BMU bit CSR_SV_IDLE. - * Add macros PHY_READ() and PHY_WRITE(). - * Rename macro SK_ADDR() to SK_HW_ADDR() - * because of conflicts with the Address Module. - * - * Revision 1.12 1998/09/16 07:25:33 malthoff - * Change the parameter order in the XM_INxx and XM_OUTxx macros, - * to have the IoC as first parameter. - * - * Revision 1.11 1998/09/03 09:58:41 malthoff - * Rework the XM_xxx macros. Use {} instead of () to - * be compatible with SK_xxx macros which are defined - * with {}. - * - * Revision 1.10 1998/09/02 11:16:39 malthoff - * Temporary modify B2_I2C_SW to make tests with - * the GE/ML prototype. - * - * Revision 1.9 1998/08/19 09:11:49 gklug - * fix: struct are removed from c-source (see CCC) - * add: typedefs for all structs - * - * Revision 1.8 1998/08/18 08:27:27 malthoff - * Add some temporary workarounds to test GE - * sources with the ML. - * - * Revision 1.7 1998/07/03 14:42:26 malthoff - * bug fix: Correct macro XMA(). - * Add temporary workaround to access the PCI config space over I/O - * - * Revision 1.6 1998/06/23 11:30:36 malthoff - * Remove ';' with ',' in macors. - * - * Revision 1.5 1998/06/22 14:20:57 malthoff - * Add macro SK_ADDR(Base,Addr). - * - * Revision 1.4 1998/06/19 13:35:43 malthoff - * change 'pGec' with 'pAC' - * - * Revision 1.3 1998/06/17 14:58:16 cvs - * Lost keywords reinserted. - * - * Revision 1.1 1998/06/17 14:16:36 cvs - * created - * - * - ******************************************************************************/ - #ifndef __INC_SKGEHW_H #define __INC_SKGEHW_H diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgehwt.h linux-2.4.26/drivers/net/sk98lin/h/skgehwt.h --- linux-2.4.25/drivers/net/sk98lin/h/skgehwt.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgehwt.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skhwt.h * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.7 $ - * Date: $Date: 2003/09/16 12:55:08 $ * Purpose: Defines for the hardware timer functions * ******************************************************************************/ @@ -22,34 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgehwt.h,v $ - * Revision 1.7 2003/09/16 12:55:08 rschmidt - * Editorial changes - * - * Revision 1.6 2003/05/13 17:57:48 mkarl - * Editorial changes. - * - * Revision 1.5 1999/11/22 13:54:24 cgoos - * Changed license header to GPL. - * - * Revision 1.4 1998/08/19 09:50:58 gklug - * fix: remove struct keyword from C-code (see CCC) add typedefs - * - * Revision 1.3 1998/08/14 07:09:29 gklug - * fix: chg pAc -> pAC - * - * Revision 1.2 1998/08/07 12:54:21 gklug - * fix: first compiled version - * - * Revision 1.1 1998/08/07 09:32:58 gklug - * first version - * - ******************************************************************************/ - /* * SKGEHWT.H contains all defines and types for the timer functions */ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgei2c.h linux-2.4.26/drivers/net/sk98lin/h/skgei2c.h --- linux-2.4.25/drivers/net/sk98lin/h/skgei2c.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgei2c.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgei2c.h * Project: Gigabit Ethernet Adapters, TWSI-Module - * Version: $Revision: 1.25 $ - * Date: $Date: 2003/10/20 09:06:05 $ * Purpose: Special defines for TWSI * ******************************************************************************/ @@ -22,100 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgei2c.h,v $ - * Revision 1.25 2003/10/20 09:06:05 rschmidt - * Editorial changes. - * - * Revision 1.24 2003/09/23 09:31:15 malthoff - * Parameter dev_size added to macro definition of SK_I2C_CTL. - * - * Revision 1.23 2002/12/19 14:34:27 rschmidt - * Added cast in macros SK_I2C_SET_BIT() and SK_I2C_CLR_BIT() - * Editorial changes (TWSI) - * - * Revision 1.22 2002/10/14 16:45:56 rschmidt - * Editorial changes (TWSI) - * - * Revision 1.21 2002/08/13 08:42:24 rschmidt - * Changed define for SK_MIN_SENSORS back to 5 - * Merged defines for PHY PLL 3V3 voltage (A and B) - * Editorial changes - * - * Revision 1.20 2002/08/06 09:43:56 jschmalz - * Extensions and changes for Yukon - * - * Revision 1.19 2002/08/02 12:00:08 rschmidt - * Added defines for YUKON sensors - * Editorial changes - * - * Revision 1.18 2001/08/16 12:44:33 afischer - * LM80 sensor init values corrected - * - * Revision 1.17 1999/11/22 13:55:25 cgoos - * Changed license header to GPL. - * - * Revision 1.16 1999/11/12 08:24:10 malthoff - * Change voltage warning and error limits - * (warning +-5%, error +-10%). - * - * Revision 1.15 1999/09/14 14:14:43 malthoff - * The 1000BT Dual Link adapter has got only one Fan. - * The second Fan has been removed. - * - * Revision 1.14 1999/05/27 13:40:50 malthoff - * Fan Divisor = 1. Assuming fan with 6500 rpm. - * - * Revision 1.13 1999/05/20 14:56:55 malthoff - * Bug Fix: Missing brace in SK_LM80_FAN_FAKTOR. - * - * Revision 1.12 1999/05/20 09:22:00 cgoos - * Changes for 1000Base-T (Fan sensors). - * - * Revision 1.11 1998/10/14 05:57:22 cgoos - * Fixed compilation warnings. - * - * Revision 1.10 1998/09/04 08:37:00 malthoff - * bugfix: correct the SK_I2C_GET_CTL() macro. - * - * Revision 1.9 1998/08/25 06:10:03 gklug - * add: thresholds for all sensors - * - * Revision 1.8 1998/08/20 11:37:42 gklug - * chg: change Ioc to IoC - * - * Revision 1.7 1998/08/20 08:53:11 gklug - * fix: compiler errors - * add: Threshold values - * - * Revision 1.6 1998/08/17 11:37:09 malthoff - * Bugfix in SK_I2C_CTL macro. The parameter 'dev' - * has to be shifted 9 bits. - * - * Revision 1.5 1998/08/17 06:52:21 malthoff - * Remove unrequired macros. - * Add macros for accessing TWSI SW register. - * - * Revision 1.4 1998/08/13 08:30:18 gklug - * add: conversion factors for read values - * add: new state SEN_VALEXT to read extension value of temperature sensor - * - * Revision 1.3 1998/08/12 13:37:56 gklug - * rmv: error numbers and messages - * - * Revision 1.2 1998/08/11 07:54:38 gklug - * add: sensor states for GE sensors - * add: Macro to access TWSI hardware register - * chg: Error messages for TWSI errors - * - * Revision 1.1 1998/07/17 11:27:56 gklug - * Created. - * - ******************************************************************************/ - /* * SKGEI2C.H contains all SK-98xx specific defines for the TWSI handling */ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgeinit.h linux-2.4.26/drivers/net/sk98lin/h/skgeinit.h --- linux-2.4.25/drivers/net/sk98lin/h/skgeinit.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgeinit.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgeinit.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.83 $ - * Date: $Date: 2003/09/16 14:07:37 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ @@ -22,353 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgeinit.h,v $ - * Revision 1.83 2003/09/16 14:07:37 rschmidt - * Moved defines for PHY power down modes from skgehw.h - * Added prototypes for SkMacClearRst() - * Editorial changes - * - * Revision 1.82 2003/09/16 07:18:36 mschmid - * Added members to port structure for MAC control - * - PMacColThres - * - PMacJamLen - * - PMacJamIpgVal - * - PMacJamIpgData - * - PMacIpgData - * - PMacLimit4 - * Added PHY power state to port structure - * - PPhyPowerState - * Added function prototypes to enter and leave low power modes - * - * Revision 1.81 2003/07/04 12:30:38 rschmidt - * Added SK_FAR to pointers in MAC statistic functions (for PXE) - * Editorial changes - * - * Revision 1.80 2003/05/28 15:25:30 rschmidt - * Added SK_FAR to pointers in MAC/PHY read functions (for PXE) - * Minor changes to avoid LINT warnings - * Editorial changes - * - * Revision 1.79 2003/05/06 12:02:33 rschmidt - * Added entry GIYukon in s_GeInit structure - * Editorial changes - * - * Revision 1.78 2003/04/28 08:59:57 rschmidt - * Added entries GIValIrqMask and GITimeStampCnt in s_GeInit structure - * - * Revision 1.77 2003/04/08 16:27:02 rschmidt - * Added entry GILedBlinkCtrl in s_GeInit structure - * Added defines for LED Blink Control - * - * Revision 1.76 2003/03/31 07:21:01 mkarl - * Added PGmANegAdv to SK_GEPORT. - * Corrected Copyright. - * - * Revision 1.75 2003/02/05 13:36:39 rschmidt - * Added define SK_FACT_78 for YUKON's Host Clock of 78.12 MHz - * Editorial changes - * - * Revision 1.74 2003/01/28 09:39:16 rschmidt - * Added entry GIYukonLite in s_GeInit structure - * Editorial changes - * - * Revision 1.73 2002/11/15 12:47:25 rschmidt - * Replaced error message SKERR_HWI_E024 for Cable Diagnostic with - * Rx queue error in SkGeStopPort(). - * - * Revision 1.72 2002/11/12 17:08:35 rschmidt - * Added entries for Cable Diagnostic to Port structure - * Added entries GIPciSlot64 and GIPciClock66 in s_GeInit structure - * Added error message for Cable Diagnostic - * Added prototypes for SkGmCableDiagStatus() - * Editorial changes - * - * Revision 1.71 2002/10/21 11:26:10 mkarl - * Changed interface of SkGeInitAssignRamToQueues(). - * - * Revision 1.70 2002/10/14 08:21:32 rschmidt - * Changed type of GICopperType, GIVauxAvail to SK_BOOL - * Added entry PRxOverCnt to Port structure - * Added entry GIYukon32Bit in s_GeInit structure - * Editorial changes - * - * Revision 1.69 2002/10/09 16:57:15 mkarl - * Added some constants and macros for SkGeInitAssignRamToQueues(). - * - * Revision 1.68 2002/09/12 08:58:51 rwahl - * Retrieve counters needed for XMAC errata workarounds directly because - * PNMI returns corrected counter values (e.g. #10620). - * - * Revision 1.67 2002/08/16 14:40:30 rschmidt - * Added entries GIGenesis and GICopperType in s_GeInit structure - * Added prototypes for SkMacHashing() - * Editorial changes - * - * Revision 1.66 2002/08/12 13:27:21 rschmidt - * Added defines for Link speed capabilities - * Added entry PLinkSpeedCap to Port structure - * Added entry GIVauxAvail in s_GeInit structure - * Added prototypes for SkMacPromiscMode() - * Editorial changes - * - * Revision 1.65 2002/08/08 15:46:18 rschmidt - * Added define SK_PHY_ACC_TO for PHY access timeout - * Added define SK_XM_RX_HI_WM for XMAC Rx High Watermark - * Added define SK_MIN_TXQ_SIZE for Min RAM Buffer Tx Queue Size - * Added entry PhyId1 to Port structure - * - * Revision 1.64 2002/07/23 16:02:56 rschmidt - * Added entry GIWolOffs in s_GeInit struct (HW-Bug in YUKON 1st rev.) - * Added prototypes for: SkGePhyRead(), SkGePhyWrite() - * - * Revision 1.63 2002/07/18 08:17:38 rwahl - * Corrected definitions for SK_LSPEED_xxx & SK_LSPEED_STAT_xxx. - * - * Revision 1.62 2002/07/17 18:21:55 rwahl - * Added SK_LSPEED_INDETERMINATED define. - * - * Revision 1.61 2002/07/17 17:16:03 rwahl - * - MacType now member of GIni struct. - * - Struct alignment to 32bit. - * - Editorial change. - * - * Revision 1.60 2002/07/15 18:23:39 rwahl - * Added GeMacFunc to GE Init structure. - * Added prototypes for SkXmUpdateStats(), SkGmUpdateStats(), - * SkXmMacStatistic(), SkGmMacStatistic(), SkXmResetCounter(), - * SkGmResetCounter(), SkXmOverflowStatus(), SkGmOverflowStatus(). - * Added defines for current link speed state. - * Added ERRMSG defintions for MacUpdateStat() & MacStatistics(). - * - * Revision 1.59 2002/07/15 15:40:22 rschmidt - * Added entry PLinkSpeedUsed to Port structure - * Editorial changes - * - * Revision 1.58 2002/06/10 09:36:30 rschmidt - * Editorial changes. - * - * Revision 1.57 2002/06/05 08:18:00 rschmidt - * Corrected alignment in Port Structure - * Added new prototypes for GMAC - * Editorial changes - * - * Revision 1.56 2002/04/25 11:38:12 rschmidt - * Added defines for Link speed values - * Added defines for Loopback parameters for MAC and PHY - * Removed entry PRxCmd from Port structure - * Added entry PLinkSpeed to Port structure - * Added entries GIChipId and GIChipRev to GE Init structure - * Removed entry GIAnyPortAct from GE Init structure - * Added prototypes for: SkMacInit(), SkMacInitPhy(), - * SkMacRxTxDisable(), SkMacSoftRst(), SkMacHardRst(), SkMacIrq(), - * SkMacIrqDisable(), SkMacFlushTxFifo(), SkMacFlushRxFifo(), - * SkMacAutoNegDone(), SkMacAutoNegLipaPhy(), SkMacSetRxTxEn(), - * SkXmPhyRead(), SkXmPhyRead(), SkGmPhyWrite(), SkGmPhyWrite(); - * Removed prototypes for static functions in SkXmac2.c - * Editorial changes - * - * Revision 1.55 2002/02/26 15:24:53 rwahl - * Fix: no link with manual configuration (#10673). The previous fix for - * #10639 was removed. So for RLMT mode = CLS the RLMT may switch to - * misconfigured port. It should not occur for the other RLMT modes. - * - * Revision 1.54 2002/01/18 16:52:52 rwahl - * Editorial corrections. - * - * Revision 1.53 2001/11/20 09:19:58 rwahl - * Reworked bugfix #10639 (no dependency to RLMT mode). - * - * Revision 1.52 2001/10/26 07:52:23 afischer - * Port switching bug in `check local link` mode - * - * Revision 1.51 2001/02/09 12:26:38 cgoos - * Inserted #ifdef DIAG for half duplex workaround timer. - * - * Revision 1.50 2001/02/07 07:56:40 rassmann - * Corrected copyright. - * - * Revision 1.49 2001/01/31 15:32:18 gklug - * fix: problem with autosensing an SR8800 switch - * add: counter for autoneg timeouts - * - * Revision 1.48 2000/11/09 11:30:10 rassmann - * WA: Waiting after releasing reset until BCom chip is accessible. - * - * Revision 1.47 2000/10/18 12:22:40 cgoos - * Added workaround for half duplex hangup. - * - * Revision 1.46 2000/08/10 11:28:00 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * - * Revision 1.45 1999/11/22 13:56:19 cgoos - * Changed license header to GPL. - * - * Revision 1.44 1999/10/26 07:34:15 malthoff - * The define SK_LNK_ON has been lost in v1.41. - * - * Revision 1.43 1999/10/06 09:30:16 cgoos - * Changed SK_XM_THR_JUMBO. - * - * Revision 1.42 1999/09/16 12:58:26 cgoos - * Changed SK_LED_STANDY macro to be independent of HW link sync. - * - * Revision 1.41 1999/07/30 06:56:14 malthoff - * Correct comment for SK_MS_STAT_UNSET. - * - * Revision 1.40 1999/05/27 13:38:46 cgoos - * Added SK_BMU_TX_WM. - * Made SK_BMU_TX_WM and SK_BMU_RX_WM user-definable. - * Changed XMAC Tx treshold to max. values. - * - * Revision 1.39 1999/05/20 14:35:26 malthoff - * Remove prototypes for SkGeLinkLED(). - * - * Revision 1.38 1999/05/19 11:59:12 cgoos - * Added SK_MS_CAP_INDETERMINATED define. - * - * Revision 1.37 1999/05/19 07:32:33 cgoos - * Changes for 1000Base-T. - * LED-defines for HWAC_LINK_LED macro. - * - * Revision 1.36 1999/04/08 14:00:24 gklug - * add:Port struct field PLinkResCt - * - * Revision 1.35 1999/03/25 07:43:07 malthoff - * Add error string for SKERR_HWI_E018MSG. - * - * Revision 1.34 1999/03/12 16:25:57 malthoff - * Remove PPollRxD and PPollTxD. - * Add SKERR_HWI_E017MSG. and SK_DPOLL_MAX. - * - * Revision 1.33 1999/03/12 13:34:41 malthoff - * Add Autonegotiation error codes. - * Change defines for parameter Mode in SkXmSetRxCmd(). - * Replace __STDC__ by SK_KR_PROTO. - * - * Revision 1.32 1999/01/25 14:40:20 mhaveman - * Added new return states for the virtual management port if multiple - * ports are active but differently configured. - * - * Revision 1.31 1998/12/11 15:17:02 gklug - * add: Link partnet autoneg states : Unknown Manual and Auto-negotiation - * - * Revision 1.30 1998/12/07 12:17:04 gklug - * add: Link Partner auto-negotiation flag - * - * Revision 1.29 1998/12/01 10:54:42 gklug - * add: variables for XMAC Errata - * - * Revision 1.28 1998/12/01 10:14:15 gklug - * add: PIsave saves the Interrupt status word - * - * Revision 1.27 1998/11/26 15:24:52 mhaveman - * Added link status states SK_LMODE_STAT_AUTOHALF and - * SK_LMODE_STAT_AUTOFULL which are used by PNMI. - * - * Revision 1.26 1998/11/26 14:53:01 gklug - * add:autoNeg Timeout variable - * - * Revision 1.25 1998/11/26 08:58:50 gklug - * add: Link Mode configuration (AUTO Sense mode) - * - * Revision 1.24 1998/11/24 13:30:27 gklug - * add: PCheckPar to port struct - * - * Revision 1.23 1998/11/18 13:23:26 malthoff - * Add SK_PKT_TO_MAX. - * - * Revision 1.22 1998/11/18 13:19:54 gklug - * add: PPrevShorts and PLinkBroken to port struct for WA XMAC Errata #C1 - * - * Revision 1.21 1998/10/26 08:02:57 malthoff - * Add GIRamOffs. - * - * Revision 1.20 1998/10/19 07:28:37 malthoff - * Add prototype for SkGeInitRamIface(). - * - * Revision 1.19 1998/10/14 14:47:48 malthoff - * SK_TIMER should not be defined for Diagnostics. - * Add SKERR_HWI_E015MSG and SKERR_HWI_E016MSG. - * - * Revision 1.18 1998/10/14 14:00:03 gklug - * add: timer to port struct for workaround of Errata #2 - * - * Revision 1.17 1998/10/14 11:23:09 malthoff - * Add prototype for SkXmAutoNegDone(). - * Fix SkXmSetRxCmd() prototype statement. - * - * Revision 1.16 1998/10/14 05:42:29 gklug - * add: HWLinkUp flag to Port struct - * - * Revision 1.15 1998/10/09 08:26:33 malthoff - * Rename SK_RB_ULPP_B to SK_RB_LLPP_B. - * - * Revision 1.14 1998/10/09 07:11:13 malthoff - * bug fix: SK_FACT_53 is 85 not 117. - * Rework time out init values. - * Add GIPortUsage and corresponding defines. - * Add some error log messages. - * - * Revision 1.13 1998/10/06 14:13:14 malthoff - * Add prototype for SkGeLoadLnkSyncCnt(). - * - * Revision 1.12 1998/10/05 11:29:53 malthoff - * bug fix: A comment was not closed. - * - * Revision 1.11 1998/10/05 08:01:59 malthoff - * Add default Timeout- Threshold- and - * Watermark constants. Add QRam start and end - * variables. Also add vars to store the polling - * mode and receive command. Add new Error Log - * Messages and function prototypes. - * - * Revision 1.10 1998/09/28 13:34:48 malthoff - * Add mode bits for LED functions. - * Move Autoneg and Flow Ctrl bits from shgesirq.h - * Add the required Error Log Entries - * and Function Prototypes. - * - * Revision 1.9 1998/09/16 14:38:41 malthoff - * Rework the SK_LNK_xxx defines. - * Add error log message defines. - * Add prototypes for skxmac2.c - * - * Revision 1.8 1998/09/11 05:29:18 gklug - * add: init state of a port - * - * Revision 1.7 1998/09/08 08:35:52 gklug - * add: defines of the Init Levels - * - * Revision 1.6 1998/09/03 13:48:42 gklug - * add: Link strati, capabilities to Port struct - * - * Revision 1.5 1998/09/03 13:30:59 malthoff - * Add SK_LNK_BLINK and SK_LNK_PERM. - * - * Revision 1.4 1998/09/03 09:55:31 malthoff - * Add constants for parameters Dir and RstMode - * when calling SkGeStopPort(). - * Rework the prototype section. - * Add Queue Address offsets PRxQOff, PXsQOff, and PXaQOff. - * Remove Ioc with IoC. - * - * Revision 1.3 1998/08/19 09:11:54 gklug - * fix: struct are removed from c-source (see CCC) - * add: typedefs for all structs - * - * Revision 1.2 1998/07/28 12:38:26 malthoff - * The prototypes got the parameter 'IoC'. - * - * Revision 1.1 1998/07/23 09:50:24 malthoff - * Created. - * - ******************************************************************************/ - #ifndef __INC_SKGEINIT_H_ #define __INC_SKGEINIT_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgepnm2.h linux-2.4.26/drivers/net/sk98lin/h/skgepnm2.h --- linux-2.4.25/drivers/net/sk98lin/h/skgepnm2.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgepnm2.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgepnm2.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.36 $ - * Date: $Date: 2003/05/23 12:45:13 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -22,144 +20,6 @@ * ******************************************************************************/ -/***************************************************************************** - * - * History: - * - * $Log: skgepnm2.h,v $ - * Revision 1.36 2003/05/23 12:45:13 tschilli - * #ifndef SK_PNMI_HUNDREDS_SEC added to SK_PNMI_HUNDREDS_SEC definition - * to allow own time macro defines. - * - * Revision 1.35 2003/03/27 11:27:48 tschilli - * Copyright messages changed. - * - * Revision 1.34 2002/12/16 09:05:18 tschilli - * Code for VCT handling added. - * - * Revision 1.33 2002/09/10 09:00:03 rwahl - * Adapted boolean definitions according sktypes. - * - * Revision 1.32 2002/08/09 09:47:01 rwahl - * Added write-only flag to oid access defines. - * Editorial changes. - * - * Revision 1.31 2002/07/17 19:23:18 rwahl - * - Replaced MAC counter definitions by enumeration. - * - Added definition SK_PNMI_MAC_TYPES. - * - Added chipset defnition for Yukon. - * - * Revision 1.30 2001/02/06 10:03:41 mkunz - * - Pnmi V4 dual net support added. Interface functions and macros extended - * - Vpd bug fixed - * - OID_SKGE_MTU added - * - * Revision 1.29 2001/01/22 13:41:37 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.28 2000/08/03 15:12:48 rwahl - * - Additional comment for MAC statistic data structure. - * - * Revision 1.27 2000/08/01 16:10:18 rwahl - * - Added mac statistic data structure for StatRxLongFrame counter. - * - * Revision 1.26 2000/03/31 13:51:34 rwahl - * Added SK_UPTR cast to offset calculation for PNMI struct fields; - * missing cast caused compiler warnings by Win64 compiler. - * - * Revision 1.25 1999/11/22 13:57:41 cgoos - * Changed license header to GPL. - * Allowing overwrite for SK_PNMI_STORE/_READ defines. - * - * Revision 1.24 1999/04/13 15:11:11 mhaveman - * Changed copyright. - * - * Revision 1.23 1999/01/28 15:07:12 mhaveman - * Changed default threshold for port switches per hour from 10 - * to 240 which means 4 switches per minute. This fits better - * the granularity of 32 for the port switch estimate - * counter. - * - * Revision 1.22 1999/01/05 12:52:30 mhaveman - * Removed macro SK_PNMI_MICRO_SEC. - * - * Revision 1.21 1999/01/05 12:50:34 mhaveman - * Enlarged macro definition SK_PNMI_HUNDREDS_SEC() so that no 64-bit - * arithmetic is necessary if SK_TICKS_PER_SEC is 100. - * - * Revision 1.20 1998/12/09 14:02:53 mhaveman - * Defined macro SK_PNMI_DEF_RLMT_CHG_THRES for default port switch - * threshold. - * - * Revision 1.19 1998/12/03 11:28:41 mhaveman - * Removed SK_PNMI_CHECKPTR macro. - * - * Revision 1.18 1998/12/03 11:21:00 mhaveman - * -Added pointer check macro SK_PNMI_CHECKPTR - * -Added macros SK_PNMI_VPD_ARR_SIZE and SK_PNMI_VPD_STR_SIZE for - * VPD key evaluation. - * - * Revision 1.17 1998/11/20 13:20:33 mhaveman - * Fixed bug in SK_PNMI_SET_STAT macro. ErrorStatus was not correctly set. - * - * Revision 1.16 1998/11/20 08:08:49 mhaveman - * Macro SK_PNMI_CHECKFLAGS has got a if clause. - * - * Revision 1.15 1998/11/03 13:53:40 mhaveman - * Fixed alignment problem in macor SK_PNMI_SET_STAT macro. - * - * Revision 1.14 1998/10/30 15:50:13 mhaveman - * Added macro SK_PNMI_MICRO_SEC() - * - * Revision 1.13 1998/10/30 12:32:20 mhaveman - * Added forgotten cast in SK_PNMI_READ_U32 macro. - * - * Revision 1.12 1998/10/29 15:40:26 mhaveman - * -Changed SK_PNMI_TRAP_SENSOR_LEN because SensorDescr has now - * variable string length. - * -Defined SK_PNMI_CHECKFLAGS macro - * - * Revision 1.11 1998/10/29 08:53:34 mhaveman - * Removed SK_PNMI_RLM_XXX table indexed because these counters need - * not been saved over XMAC resets. - * - * Revision 1.10 1998/10/28 08:48:20 mhaveman - * -Added macros for storage according to alignment - * -Changed type of Instance to SK_U32 because of VPD - * -Removed trap structures. Not needed because of alignment problem - * -Changed type of Action form SK_U8 to int - * - * Revision 1.9 1998/10/21 13:34:45 mhaveman - * Shit, mismatched calculation of SK_PNMI_HUNDREDS_SEC. Corrected. - * - * Revision 1.8 1998/10/21 13:24:58 mhaveman - * Changed calculation of hundreds of seconds. - * - * Revision 1.7 1998/10/20 07:31:41 mhaveman - * Made type changes to unsigned int where possible. - * - * Revision 1.6 1998/09/04 17:04:05 mhaveman - * Added Sync counters to offset storage to provided settled values on - * port switch. - * - * Revision 1.5 1998/09/04 12:45:35 mhaveman - * Removed dummies for SK_DRIVER_ macros. They should be added by driver - * writer in skdrv2nd.h. - * - * Revision 1.4 1998/09/04 11:59:50 mhaveman - * Everything compiles now. Driver Macros for counting still missing. - * - * Revision 1.3 1998/08/24 12:01:35 mhaveman - * Intermediate state. - * - * Revision 1.2 1998/08/17 07:51:40 mhaveman - * Intermediate state. - * - * Revision 1.1 1998/08/11 09:08:40 mhaveman - * Intermediate state. - * - ****************************************************************************/ - #ifndef _SKGEPNM2_H_ #define _SKGEPNM2_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgepnmi.h linux-2.4.26/drivers/net/sk98lin/h/skgepnmi.h --- linux-2.4.25/drivers/net/sk98lin/h/skgepnmi.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgepnmi.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.62 $ - * Date: $Date: 2003/08/15 12:31:52 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -22,237 +20,6 @@ * ******************************************************************************/ -/***************************************************************************** - * - * History: - * - * $Log: skgepnmi.h,v $ - * Revision 1.62 2003/08/15 12:31:52 tschilli - * Added new OIDs: - * OID_SKGE_DRIVER_RELDATE - * OID_SKGE_DRIVER_FILENAME - * OID_SKGE_CHIPID - * OID_SKGE_RAMSIZE - * OID_SKGE_VAUXAVAIL - * OID_SKGE_PHY_TYPE - * OID_SKGE_PHY_LP_MODE - * - * Added new define SK_DIAG_ATTACHED for OID_SKGE_DIAG_MODE handling. - * - * Revision 1.61 2003/05/23 12:53:52 tschilli - * Generic PNMI IOCTL subcommands added. - * Function prototype SkPnmiGenIoctl() added. - * OID_SKGE_BOARDLEVEL added. - * Return value SK_PNMI_ERR_NOT_SUPPORTED added. - * Editorial changes. - * - * Revision 1.60 2003/03/27 11:27:26 tschilli - * Copyright messages changed. - * - * Revision 1.59 2002/12/16 14:03:50 tschilli - * New defines for VCT added. - * - * Revision 1.58 2002/12/16 09:04:59 tschilli - * Code for VCT handling added. - * - * Revision 1.57 2002/09/26 12:41:05 tschilli - * SK_PNMI_PORT BufPort entry in struct SK_PNMI added. - * - * Revision 1.56 2002/08/16 11:10:41 rwahl - * - Replaced c++ comment. - * - * Revision 1.55 2002/08/09 15:40:21 rwahl - * Editorial change (renamed ConfSpeedCap). - * - * Revision 1.54 2002/08/09 11:06:07 rwahl - * Added OID_SKGE_SPEED_CAP. - * - * Revision 1.53 2002/08/09 09:45:28 rwahl - * Added support for NDIS OID_PNP_xxx. - * Editorial changes. - * - * Revision 1.52 2002/08/06 17:54:07 rwahl - * - Added speed cap to PNMI config struct. - * - * Revision 1.51 2002/07/17 19:19:26 rwahl - * - Added OID_SKGE_SPEED_MODE and OID_SKGE_SPEED_STATUS. - * - Added SK_PNMI_CNT_RX_PMACC_ERR() & SK_PNMI_CNT_RX_LONGFRAMES(). - * - Added speed mode & status to PNMI config struct. - * - Editorial changes. - * - * Revision 1.50 2002/05/22 08:59:37 rwahl - * Added string definitions for error msgs. - * - * Revision 1.49 2001/11/20 09:23:50 rwahl - * - pnmi struct: reordered and aligned to 32bit. - * - * Revision 1.48 2001/02/23 14:34:24 mkunz - * Changed macro PHYS2INST. Added pAC to Interface - * - * Revision 1.47 2001/02/07 08:28:23 mkunz - * - Added Oids: OID_SKGE_DIAG_ACTION - * OID_SKGE_DIAG_RESULT - * OID_SKGE_MULTICAST_LIST - * OID_SKGE_CURRENT_PACKET_FILTER - * OID_SKGE_INTERMEDIATE_SUPPORT - * - Changed value of OID_SKGE_MTU - * - * Revision 1.46 2001/02/06 10:01:41 mkunz - * - Pnmi V4 dual net support added. Interface functions and macros extended - * - Vpd bug fixed - * - OID_SKGE_MTU added - * - * Revision 1.45 2001/01/22 13:41:37 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.44 2000/09/07 07:35:27 rwahl - * - removed NDIS counter specific data type. - * - fixed spelling for OID_SKGE_RLMT_PORT_PREFERRED. - * - * Revision 1.43 2000/08/04 11:41:08 rwahl - * - Fixed compiler warning (port is always >= 0) for macros - * SK_PNMI_CNT_RX_LONGFRAMES & SK_PNMI_CNT_SYNC_OCTETS - * - * Revision 1.42 2000/08/03 15:14:07 rwahl - * - Corrected error in driver macros addressing a physical port. - * - * Revision 1.41 2000/08/01 16:22:29 rwahl - * - Changed MDB version to 3.1. - * - Added definitions for StatRxLongFrames counter. - * - Added macro to be used by driver to count long frames received. - * - Added directive to control width (default = 32bit) of NDIS statistic - * counters (SK_NDIS_64BIT_CTR). - * - * Revision 1.40 2000/03/31 13:51:34 rwahl - * Added SK_UPTR cast to offset calculation for PNMI struct fields; - * missing cast caused compiler warnings by Win64 compiler. - * - * Revision 1.39 1999/12/06 10:09:47 rwahl - * Added new error log message. - * - * Revision 1.38 1999/11/22 13:57:55 cgoos - * Changed license header to GPL. - * - * Revision 1.37 1999/09/14 14:25:32 rwahl - * Set MDB version for 1000Base-T (sensors, Master/Slave) changes. - * - * Revision 1.36 1999/05/20 09:24:56 cgoos - * Changes for 1000Base-T (sensors, Master/Slave). - * - * Revision 1.35 1999/04/13 15:10:51 mhaveman - * Replaced RLMT macros SK_RLMT_CHECK_xxx again by those of PNMI to - * grant unified interface. But PNMI macros will store the same - * value as RLMT macros. - * - * Revision 1.34 1999/04/13 15:03:49 mhaveman - * -Changed copyright - * -Removed SK_PNMI_RLMT_MODE_CHK_xxx macros. Those of RLMT should be - * used. - * - * Revision 1.33 1999/03/23 10:41:02 mhaveman - * Changed comments. - * - * Revision 1.32 1999/01/25 15:01:33 mhaveman - * Added support for multiple simultaniously active ports. - * - * Revision 1.31 1999/01/19 10:06:26 mhaveman - * Added new error log message. - * - * Revision 1.30 1999/01/05 10:34:49 mhaveman - * Fixed little error in RlmtChangeEstimate calculation. - * - * Revision 1.29 1999/01/05 09:59:41 mhaveman - * Redesigned port switch average calculation to avoid 64bit - * arithmetic. - * - * Revision 1.28 1998/12/08 10:05:48 mhaveman - * Defined macro SK_PNMI_MIN_STRUCT_SIZE. - * - * Revision 1.27 1998/12/03 14:39:35 mhaveman - * Fixed problem that LSTAT was enumerated wrong. - * - * Revision 1.26 1998/12/03 11:19:51 mhaveman - * Changed contents of errlog message SK_PNMI_ERR016MSG - * - * Revision 1.25 1998/12/01 10:40:04 mhaveman - * Changed size of SensorNumber, ChecksumNumber and RlmtPortNumber in - * SK_PNMI_STRUCT_DATA to be conform with OID definition. - * - * Revision 1.24 1998/11/20 08:09:27 mhaveman - * Added macros to convert between logical, physical port indexes and - * instances. - * - * Revision 1.23 1998/11/10 13:41:13 mhaveman - * Needed to change interface, because NT driver needs a return value - * of needed buffer space on TOO_SHORT errors. Therefore all - * SkPnmiGet/Preset/Set functions now have a pointer to the length - * parameter, where the needed space on error is returned. - * - * Revision 1.22 1998/11/03 12:05:51 mhaveman - * Added pAC parameter to counter macors. - * - * Revision 1.21 1998/11/02 10:47:36 mhaveman - * Added syslog messages for internal errors. - * - * Revision 1.20 1998/10/30 15:49:36 mhaveman - * -Removed unused SK_PNMI_UTILIZATION_BASE and EstOldCnt. - * -Redefined SK_PNMI_CHG_EST_BASE to hundreds of seconds. - * - * Revision 1.19 1998/10/29 15:38:44 mhaveman - * Changed string lengths of PNMI_STRUCT_DATA structure because - * string OIDs are now encoded with leading length ocetet. - * - * Revision 1.18 1998/10/29 08:52:27 mhaveman - * -Added byte to strings in PNMI_STRUCT_DATA structure. - * -Shortened SK_PNMI_RLMT structure to SK_MAX_MACS elements. - * - * Revision 1.17 1998/10/28 08:49:50 mhaveman - * -Changed type of Instance back to SK_U32 because of VPD - * -Changed type from SK_U8 to char of PciBusSpeed, PciBusWidth, PMD, - * and Connector. - * - * Revision 1.16 1998/10/22 10:42:31 mhaveman - * -Removed (SK_U32) casts for OIDs - * -excluded NDIS OIDs when they are already defined with ifndef _NDIS_ - * - * Revision 1.15 1998/10/20 13:56:28 mhaveman - * Headerfile includes now directly other header files to comile correctly. - * - * Revision 1.14 1998/10/20 07:31:09 mhaveman - * Made type changes to unsigned int where possible. - * - * Revision 1.13 1998/10/19 10:53:13 mhaveman - * -Casted OID definitions to SK_U32 - * -Renamed RlmtMAC... to RlmtPort... - * -Changed wrong type of VpdEntriesList from SK_U32 to char * - * - * Revision 1.12 1998/10/13 07:42:27 mhaveman - * -Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA - * -Removed old cvs history entries - * -Renamed MacNumber to PortNumber - * - * Revision 1.11 1998/10/07 10:55:24 mhaveman - * -Added OID_MDB_VERSION. Therefore was a renumbering of the VPD OIDs - * necessary. - * -Added OID_GEN_ Ids to support the windows driver. - * - * Revision 1.10 1998/09/30 13:41:10 mhaveman - * Renamed some OIDs to reduce usage of 'MAC' which is replaced by 'PORT'. - * - * Revision 1.9 1998/09/04 17:06:17 mhaveman - * -Added SyncCounter as macro. - * -Renamed OID_SKGE_.._NO_DESCR_CTS to OID_SKGE_.._NO_BUF_CTS. - * -Added macros for driver description and version strings. - * - * Revision 1.8 1998/09/04 14:36:52 mhaveman - * Added OIDs and Structure to access value of macro counters which are - * counted by the driver. - * - * Revision 1.7 1998/09/04 11:59:36 mhaveman - * Everything compiles now. Driver Macros for counting still missing. - * - ****************************************************************************/ - #ifndef _SKGEPNMI_H_ #define _SKGEPNMI_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skgesirq.h linux-2.4.26/drivers/net/sk98lin/h/skgesirq.h --- linux-2.4.25/drivers/net/sk98lin/h/skgesirq.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skgesirq.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgesirq.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.30 $ - * Date: $Date: 2003/07/04 12:34:13 $ * Purpose: SK specific Gigabit Ethernet special IRQ functions * ******************************************************************************/ @@ -22,111 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: skgesirq.h,v $ - * Revision 1.30 2003/07/04 12:34:13 rschmidt - * Added SKERR_SIRQ_E025 for Downshift detected (Yukon-Copper) - * - * Revision 1.29 2003/05/28 15:14:49 rschmidt - * Moved defines for return codes of SkGePortCheckUp() to header file. - * Minor changes to avoid LINT warnings. - * - * Revision 1.28 2003/05/13 17:22:43 mkarl - * Editorial changes. - * - * Revision 1.27 2003/03/31 07:32:34 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.26 2002/10/14 09:52:36 rschmidt - * Added SKERR_SIRQ_E023 and SKERR_SIRQ_E024 for GPHY (Yukon) - * Editorial changes - * - * Revision 1.25 2002/07/15 18:15:52 rwahl - * Editorial changes. - * - * Revision 1.24 2002/07/15 15:39:21 rschmidt - * Corrected define for SKERR_SIRQ_E022 - * Editorial changes - * - * Revision 1.23 2002/04/25 11:09:45 rschmidt - * Removed declarations for SkXmInitPhy(), SkXmRxTxEnable() - * Editorial changes - * - * Revision 1.22 2000/11/09 11:30:10 rassmann - * WA: Waiting after releasing reset until BCom chip is accessible. - * - * Revision 1.21 2000/10/18 12:22:40 cgoos - * Added workaround for half duplex hangup. - * - * Revision 1.20 1999/12/06 10:00:44 cgoos - * Added SET event for role. - * - * Revision 1.19 1999/11/22 13:58:26 cgoos - * Changed license header to GPL. - * - * Revision 1.18 1999/05/19 07:32:59 cgoos - * Changes for 1000Base-T. - * - * Revision 1.17 1999/03/12 13:29:31 malthoff - * Move Autonegotiation Error Codes to skgeinit.h. - * - * Revision 1.16 1999/03/08 10:11:28 gklug - * add: AutoNegDone return codes - * - * Revision 1.15 1998/11/18 13:20:53 gklug - * add: different timeouts for active and non-active links - * - * Revision 1.14 1998/11/04 07:18:14 cgoos - * Added prototype for SkXmRxTxEnable. - * - * Revision 1.13 1998/10/21 05:52:23 gklug - * add: parameter DoLoop to InitPhy function - * - * Revision 1.12 1998/10/19 06:45:03 cgoos - * Added prototype for SkXmInitPhy. - * - * Revision 1.11 1998/10/15 14:34:10 gklug - * add: WA_TIME is 500 msec - * - * Revision 1.10 1998/10/14 14:49:41 malthoff - * Remove err log defines E021 and E022. They are - * defined in skgeinit.h now. - * - * Revision 1.9 1998/10/14 14:00:39 gklug - * add: error logs for init phys - * - * Revision 1.8 1998/10/14 05:44:05 gklug - * add: E020 - * - * Revision 1.7 1998/10/02 06:24:58 gklug - * add: error messages - * - * Revision 1.6 1998/10/01 07:54:45 gklug - * add: PNMI debug module - * - * Revision 1.5 1998/09/28 13:36:31 malthoff - * Move the bit definitions for Autonegotiation - * and Flow Control to skgeinit.h. - * - * Revision 1.4 1998/09/15 12:29:34 gklug - * add: error logs - * - * Revision 1.3 1998/09/03 13:54:02 gklug - * add: function prototypes - * - * Revision 1.2 1998/09/03 10:24:36 gklug - * add: Events send by PNMI - * add: parameter definition for Flow Control etc. - * - * Revision 1.1 1998/08/27 11:50:27 gklug - * initial revision - * - * - ******************************************************************************/ - #ifndef _INC_SKGESIRQ_H_ #define _INC_SKGESIRQ_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/ski2c.h linux-2.4.26/drivers/net/sk98lin/h/ski2c.h --- linux-2.4.25/drivers/net/sk98lin/h/ski2c.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/ski2c.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: ski2c.h * Project: Gigabit Ethernet Adapters, TWSI-Module - * Version: $Revision: 1.35 $ - * Date: $Date: 2003/10/20 09:06:30 $ * Purpose: Defines to access Voltage and Temperature Sensor * ******************************************************************************/ @@ -22,128 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: ski2c.h,v $ - * Revision 1.35 2003/10/20 09:06:30 rschmidt - * Added prototypes for SkI2cRead() and SkI2cWrite(). - * Editorial changes. - * - * Revision 1.34 2003/01/28 09:11:21 rschmidt - * Editorial changes - * - * Revision 1.33 2002/10/14 16:40:50 rschmidt - * Editorial changes (TWSI) - * - * Revision 1.32 2002/08/13 08:55:07 rschmidt - * Editorial changes - * - * Revision 1.31 2002/08/06 09:44:22 jschmalz - * Extensions and changes for Yukon - * - * Revision 1.30 2001/04/05 11:38:09 rassmann - * Set SenState to idle in SkI2cWaitIrq(). - * Changed error message in SkI2cWaitIrq(). - * - * Revision 1.29 2000/08/03 14:28:17 rassmann - * - Added function to wait for I2C being ready before resetting the board. - * - Replaced one duplicate "out of range" message with correct one. - * - * Revision 1.28 1999/11/22 13:55:46 cgoos - * Changed license header to GPL. - * - * Revision 1.27 1999/05/20 09:23:10 cgoos - * Changes for 1000Base-T (Fan sensors). - * - * Revision 1.26 1998/12/01 13:45:47 gklug - * add: InitLevel to I2c struct - * - * Revision 1.25 1998/11/03 06:55:16 gklug - * add: Dummy Reads to I2c struct - * - * Revision 1.24 1998/10/02 14:28:59 cgoos - * Added prototype for SkI2cIsr. - * - * Revision 1.23 1998/09/08 12:20:11 gklug - * add: prototypes for init and read functions - * - * Revision 1.22 1998/09/08 07:37:56 gklug - * add: log error if PCI_IO voltage sensor could not be initialized - * - * Revision 1.21 1998/09/04 08:38:05 malthoff - * Change the values for I2C_READ and I2C_WRITE - * - * Revision 1.20 1998/08/25 07:52:22 gklug - * chg: Timestamps (last) added for logging - * - * Revision 1.19 1998/08/25 06:09:00 gklug - * rmv: warning and error levels of the individual sensors. - * add: timing definitions for sending traps and logging errors - * - * Revision 1.18 1998/08/20 11:41:15 gklug - * chg: omit STRCPY macro by using char * as Sensor Description - * - * Revision 1.17 1998/08/20 11:37:43 gklug - * chg: change Ioc to IoC - * - * Revision 1.16 1998/08/20 11:30:38 gklug - * fix: SenRead declaration - * - * Revision 1.15 1998/08/20 11:27:53 gklug - * fix: Compile bugs with new awrning constants - * - * Revision 1.14 1998/08/20 08:53:12 gklug - * fix: compiler errors - * add: Threshold values - * - * Revision 1.13 1998/08/19 12:21:16 gklug - * fix: remove struct from C files (see CCC) - * add: typedefs for all structs - * - * Revision 1.12 1998/08/19 10:57:41 gklug - * add: Warning levels - * - * Revision 1.11 1998/08/18 08:37:02 malthoff - * Prototypes not required for SK_DIAG. - * - * Revision 1.10 1998/08/17 13:54:00 gklug - * fix: declaration of event function - * - * Revision 1.9 1998/08/17 06:48:39 malthoff - * Remove some unrequired macros. - * Fix the compiler errors. - * - * Revision 1.8 1998/08/14 06:47:19 gklug - * fix: Values are intergers - * - * Revision 1.7 1998/08/14 06:26:05 gklug - * add: Init error message - * - * Revision 1.6 1998/08/13 08:31:08 gklug - * add: Error message - * - * Revision 1.5 1998/08/12 14:32:04 gklug - * add: new error code/message - * - * Revision 1.4 1998/08/12 13:39:08 gklug - * chg: names of error messages - * add: defines for Sensor type and thresholds - * - * Revision 1.3 1998/08/11 07:57:16 gklug - * add: sensor struct - * add: Timeout defines - * add: I2C control struct for pAC - * - * Revision 1.2 1998/07/17 11:29:02 gklug - * rmv: Microwire and SMTPANIC - * - * Revision 1.1 1998/06/19 14:30:10 malthoff - * Created. Sources taken from ML Project. - * - ******************************************************************************/ - /* * SKI2C.H contains all I2C specific defines */ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skqueue.h linux-2.4.26/drivers/net/sk98lin/h/skqueue.h --- linux-2.4.25/drivers/net/sk98lin/h/skqueue.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skqueue.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skqueue.h * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.16 $ - * Date: $Date: 2003/09/16 12:50:32 $ * Purpose: Defines for the Event queue * ******************************************************************************/ @@ -22,68 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skqueue.h,v $ - * Revision 1.16 2003/09/16 12:50:32 rschmidt - * Editorial changes - * - * Revision 1.15 2003/05/13 17:54:57 mkarl - * Editorial changes. - * - * Revision 1.14 2002/03/15 10:52:13 mkunz - * Added event classes for link aggregation - * - * Revision 1.13 1999/11/22 13:59:05 cgoos - * Changed license header to GPL. - * - * Revision 1.12 1998/09/08 08:48:01 gklug - * add: init level handling - * - * Revision 1.11 1998/09/03 14:15:11 gklug - * add: CSUM and HWAC Eventclass and function. - * fix: pParaPtr according to CCC - * - * Revision 1.10 1998/08/20 12:43:03 gklug - * add: typedef SK_QUEUE - * - * Revision 1.9 1998/08/19 09:50:59 gklug - * fix: remove struct keyword from C-code (see CCC) add typedefs - * - * Revision 1.8 1998/08/18 07:00:01 gklug - * fix: SK_PTR not defined use void * instead. - * - * Revision 1.7 1998/08/17 13:43:19 gklug - * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR - * - * Revision 1.6 1998/08/14 07:09:30 gklug - * fix: chg pAc -> pAC - * - * Revision 1.5 1998/08/11 14:26:44 gklug - * chg: Event Dispatcher returns now int. - * - * Revision 1.4 1998/08/11 12:15:21 gklug - * add: Error numbers of skqueue module - * - * Revision 1.3 1998/08/07 12:54:23 gklug - * fix: first compiled version - * - * Revision 1.2 1998/08/07 09:34:00 gklug - * adapt structure defs to CCC - * add: prototypes for functions - * - * Revision 1.1 1998/07/30 14:52:12 gklug - * Initial version. - * Defines Event Classes, Event structs and queue management variables. - * - ******************************************************************************/ - -/* - * SKQUEUE.H contains all defines and types for the event queue - */ - #ifndef _SKQUEUE_H_ #define _SKQUEUE_H_ diff -urN linux-2.4.25/drivers/net/sk98lin/h/skrlmt.h linux-2.4.26/drivers/net/sk98lin/h/skrlmt.h --- linux-2.4.25/drivers/net/sk98lin/h/skrlmt.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skrlmt.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skrlmt.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.37 $ - * Date: $Date: 2003/04/15 09:43:43 $ * Purpose: Header file for Redundant Link ManagemenT. * ******************************************************************************/ @@ -24,137 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skrlmt.h,v $ - * Revision 1.37 2003/04/15 09:43:43 tschilli - * Copyright messages changed. - * - * Revision 1.36 2003/04/14 15:56:22 tschilli - * "#error C++ is not yet supported." removed. - * - * Revision 1.35 2003/01/31 14:12:41 mkunz - * single port adapter runs now with two identical MAC addresses - * - * Revision 1.34 2002/09/23 15:13:41 rwahl - * Editorial changes. - * - * Revision 1.33 2001/07/03 12:16:48 mkunz - * New Flag ChgBcPrio (Change priority of last broadcast received) - * - * Revision 1.32 2001/02/14 14:06:31 rassmann - * Editorial changes. - * - * Revision 1.31 2001/02/05 14:25:26 rassmann - * Prepared RLMT for transparent operation. - * - * Revision 1.30 2001/01/22 13:41:39 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.29 2000/11/17 08:58:00 rassmann - * Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event. - * - * Revision 1.28 2000/11/09 12:24:34 rassmann - * Editorial changes. - * - * Revision 1.27 1999/11/22 13:59:56 cgoos - * Changed license header to GPL. - * - * Revision 1.26 1999/10/04 14:01:19 rassmann - * Corrected reaction to reception of BPDU frames (#10441). - * - * Revision 1.25 1999/07/20 12:53:39 rassmann - * Fixed documentation errors for lookahead macros. - * - * Revision 1.24 1999/05/28 11:15:56 rassmann - * Changed behaviour to reflect Design Spec v1.2. - * Controlling Link LED(s). - * Introduced RLMT Packet Version field in RLMT Packet. - * Newstyle lookahead macros (checking meta-information before looking at - * the packet). - * - * Revision 1.23 1999/01/28 12:50:42 rassmann - * Not using broadcast time stamps in CheckLinkState mode. - * - * Revision 1.22 1999/01/27 14:13:04 rassmann - * Monitoring broadcast traffic. - * Switching more reliably and not too early if switch is - * configured for spanning tree. - * - * Revision 1.21 1998/12/08 13:11:25 rassmann - * Stopping SegTimer at RlmtStop. - * - * Revision 1.20 1998/11/24 12:37:33 rassmann - * Implemented segmentation check. - * - * Revision 1.19 1998/11/17 13:43:06 rassmann - * Handling (logical) tx failure. - * Sending packet on logical address after PORT_SWITCH. - * - * Revision 1.18 1998/11/13 16:56:56 rassmann - * Added macro version of SkRlmtLookaheadPacket. - * - * Revision 1.17 1998/11/06 18:06:05 rassmann - * Corrected timing when RLMT checks fail. - * Clearing tx counter earlier in periodical checks. - * - * Revision 1.16 1998/11/03 13:53:50 rassmann - * RLMT should switch now (at least in mode 3). - * - * Revision 1.15 1998/10/22 11:39:52 rassmann - * Corrected signed/unsigned mismatches. - * Corrected receive list handling and address recognition. - * - * Revision 1.14 1998/10/15 15:16:36 rassmann - * Finished Spanning Tree checking. - * Checked with lint. - * - * Revision 1.13 1998/09/24 19:16:08 rassmann - * Code cleanup. - * Introduced Timer for PORT_DOWN due to no RX. - * - * Revision 1.12 1998/09/16 11:09:52 rassmann - * Syntax corrections. - * - * Revision 1.11 1998/09/15 11:28:50 rassmann - * Syntax corrections. - * - * Revision 1.10 1998/09/14 17:07:38 rassmann - * Added code for port checking via LAN. - * Changed Mbuf definition. - * - * Revision 1.9 1998/09/07 11:14:15 rassmann - * Syntax corrections. - * - * Revision 1.8 1998/09/07 09:06:08 rassmann - * Syntax corrections. - * - * Revision 1.7 1998/09/04 19:41:34 rassmann - * Syntax corrections. - * Started entering code for checking local links. - * - * Revision 1.6 1998/09/04 12:14:28 rassmann - * Interface cleanup. - * - * Revision 1.5 1998/09/02 16:55:29 rassmann - * Updated to reflect new DRV/HWAC/RLMT interface. - * - * Revision 1.4 1998/09/02 07:26:02 afischer - * typedef for SK_RLMT_PORT - * - * Revision 1.3 1998/08/27 14:29:03 rassmann - * Code cleanup. - * - * Revision 1.2 1998/08/27 14:26:25 rassmann - * Updated interface. - * - * Revision 1.1 1998/08/21 08:29:10 rassmann - * First public version. - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This is the header file for Redundant Link ManagemenT. diff -urN linux-2.4.25/drivers/net/sk98lin/h/sktimer.h linux-2.4.26/drivers/net/sk98lin/h/sktimer.h --- linux-2.4.25/drivers/net/sk98lin/h/sktimer.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/sktimer.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: sktimer.h * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/09/16 12:58:18 $ * Purpose: Defines for the timer functions * ******************************************************************************/ @@ -22,48 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: sktimer.h,v $ - * Revision 1.11 2003/09/16 12:58:18 rschmidt - * Editorial changes - * - * Revision 1.10 2003/05/13 17:56:44 mkarl - * Editorial changes. - * - * Revision 1.9 1999/11/22 14:00:29 cgoos - * Changed license header to GPL. - * - * Revision 1.8 1998/09/08 08:48:02 gklug - * add: init level handling - * - * Revision 1.7 1998/08/20 12:31:29 gklug - * fix: SK_TIMCTRL needs to be defined - * - * Revision 1.6 1998/08/19 09:51:00 gklug - * fix: remove struct keyword from C-code (see CCC) add typedefs - * - * Revision 1.5 1998/08/17 13:43:21 gklug - * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR - * - * Revision 1.4 1998/08/14 07:09:31 gklug - * fix: chg pAc -> pAC - * - * Revision 1.3 1998/08/07 12:54:24 gklug - * fix: first compiled version - * - * Revision 1.2 1998/08/07 09:35:29 gklug - * add: Timer control struct for Adapters context - * add: function prototypes - * - * Revision 1.1 1998/08/05 11:27:01 gklug - * First version: adapted from SMT - * - * - ******************************************************************************/ - /* * SKTIMER.H contains all defines and types for the timer functions */ diff -urN linux-2.4.25/drivers/net/sk98lin/h/sktypes.h linux-2.4.26/drivers/net/sk98lin/h/sktypes.h --- linux-2.4.25/drivers/net/sk98lin/h/sktypes.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/sktypes.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: sktypes.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: Define data types for Linux * ******************************************************************************/ @@ -22,31 +20,6 @@ * ******************************************************************************/ - /***************************************************************************** - * - * History: - * - * $Log: sktypes.h,v $ - * Revision 1.2 2003/10/07 08:16:51 mlindner - * Fix: Copyright changes - * - * Revision 1.1 2003/07/21 07:26:01 rroesler - * Fix: Re-Enter after CVS crash - * - * Revision 1.3 2003/02/25 14:16:40 mlindner - * Fix: Copyright statement - * - * Revision 1.2 1999/11/22 14:01:58 cgoos - * Changed license header to GPL. - * Now using Linux' fixed size types instead of standard types. - * - * Revision 1.1 1999/02/16 07:41:40 cgoos - * First version. - * - * - * - *****************************************************************************/ - /****************************************************************************** * * Description: diff -urN linux-2.4.25/drivers/net/sk98lin/h/skversion.h linux-2.4.26/drivers/net/sk98lin/h/skversion.h --- linux-2.4.25/drivers/net/sk98lin/h/skversion.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skversion.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: version.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.5 $ - * Date: $Date: 2003/10/07 08:16:51 $ * Purpose: SK specific Error log support * ******************************************************************************/ @@ -22,42 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * $Log: skversion.h,v $ - * Revision 1.5 2003/10/07 08:16:51 mlindner - * Fix: Copyright changes - * - * Revision 1.4 2003/09/22 08:40:10 mlindner - * Add: Added DRIVER_FILE_NAME and DRIVER_REL_DATE - * - * Revision 1.3 2003/08/25 13:34:48 mlindner - * Fix: Lint changes - * - * Revision 1.2 2003/08/13 12:01:01 mlindner - * Add: Changes for Lint - * - * Revision 1.1 2003/07/24 09:29:56 rroesler - * Fix: Re-Enter after CVS crash - * - * Revision 1.4 2003/02/25 14:16:40 mlindner - * Fix: Copyright statement - * - * Revision 1.3 2003/02/25 13:30:18 mlindner - * Add: Support for various vendors - * - * Revision 1.1.2.1 2001/09/05 13:38:30 mlindner - * Removed FILE description - * - * Revision 1.1 2001/03/06 09:25:00 mlindner - * first version - * - * - * - ******************************************************************************/ - - #ifdef lint static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH."; static const char SysKonnectBuildNumber[] = diff -urN linux-2.4.25/drivers/net/sk98lin/h/skvpd.h linux-2.4.26/drivers/net/sk98lin/h/skvpd.h --- linux-2.4.25/drivers/net/sk98lin/h/skvpd.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/skvpd.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skvpd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.15 $ - * Date: $Date: 2003/01/13 10:39:38 $ * Purpose: Defines and Macros for VPD handling * ******************************************************************************/ @@ -21,70 +19,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skvpd.h,v $ - * Revision 1.15 2003/01/13 10:39:38 rschmidt - * Replaced define for PCI device Id for YUKON with GENESIS - * Editorial changes - * - * Revision 1.14 2002/11/14 15:18:10 gheinig - * Added const specifier to key and buf parameters for VpdPara,VpdRead - * and VpdWrite. This is necessary for the Diag 7 GUI API - * - * Revision 1.13 2002/10/14 15:58:18 rschmidt - * Added entry in rom_size struct s_vpd - * Editorial changes - * - * Revision 1.12 2002/09/09 14:43:51 mkarl - * added PCI Id of Yukon for reading VPD in diag before the adapter has - * been initialized - * editorial changes - * - * Revision 1.11 2002/07/26 13:19:16 mkarl - * added support for Yukon - * added vpd_size to VPD struct - * - * Revision 1.10 2000/08/10 11:29:07 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * Removed unused function VpdWriteDword() (#if 0). - * Made VpdReadKeyword() available for SKDIAG only. - * - * Revision 1.9 1999/11/22 14:02:27 cgoos - * Changed license header to GPL. - * - * Revision 1.8 1999/03/11 14:26:40 malthoff - * Replace __STDC__ with SK_KR_PROTO. - * - * Revision 1.7 1998/10/28 07:27:17 gklug - * rmv: SWAP macros - * add: VPD_IN/OUT8 macros - * chg: interface definition - * - * Revision 1.6 1998/10/22 10:03:44 gklug - * fix: use SK_OUT16 instead of SK_OUTW - * - * Revision 1.5 1998/10/14 07:05:31 cgoos - * Changed constants in SK_SWAP_32 to UL. - * - * Revision 1.4 1998/08/19 08:14:09 gklug - * fix: remove struct keyword as much as possible from the C-code (see CCC) - * - * Revision 1.3 1998/08/18 08:18:56 malthoff - * Modify VPD in and out macros for SK_DIAG - * - * Revision 1.2 1998/07/03 14:49:08 malthoff - * Add VPD_INxx() and VPD_OUTxx() macros for the Diagnostics tool. - * - * Revision 1.1 1998/06/19 14:08:03 malthoff - * Created. - * - * - ******************************************************************************/ - /* * skvpd.h contains Diagnostic specific defines for VPD handling */ diff -urN linux-2.4.25/drivers/net/sk98lin/h/xmac_ii.h linux-2.4.26/drivers/net/sk98lin/h/xmac_ii.h --- linux-2.4.25/drivers/net/sk98lin/h/xmac_ii.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/h/xmac_ii.h 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: xmac_ii.h * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.52 $ - * Date: $Date: 2003/10/02 16:35:50 $ * Purpose: Defines and Macros for Gigabit Ethernet Controller * ******************************************************************************/ @@ -22,207 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: xmac_ii.h,v $ - * Revision 1.52 2003/10/02 16:35:50 rschmidt - * Added defines for default values of GMAC parameters - * Changed defines for setting GMAC parameters - * Editorial changes - * - * Revision 1.51 2003/09/23 09:04:27 malthoff - * Add bit definitions for PHY_MARV_EXT_P_STAT. - * - * Revision 1.50 2003/09/16 14:15:07 rschmidt - * Added defines for Extended PHY Specific Control - * Editorial changes - * - * Revision 1.49 2003/09/16 07:22:46 mschmid - * Added defines for Marvell PHY energy detect modes - * Added macros for MAC parameter setting in port structure - * - * Revision 1.48 2003/05/13 17:17:55 mkarl - * Editorial changes. - * - * Revision 1.47 2003/03/31 07:37:25 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.46 2003/01/28 09:47:45 rschmidt - * Added defines for copper MDI/MDIX configuration - * Added defines for LED Control Register - * Editorial changes - * - * Revision 1.45 2002/12/10 14:35:13 rschmidt - * Corrected defines for Extended PHY Specific Control - * Added defines for Ext. PHY Specific Ctrl 2 Reg. (Fiber specific) - * - * Revision 1.44 2002/12/09 14:58:41 rschmidt - * Added defines for Ext. PHY Specific Ctrl Reg. (downshift feature) - * Added 'GMR_FS_UN_SIZE'-Bit to Rx GMAC FIFO Flush Mask - * - * Revision 1.43 2002/12/05 10:14:45 rschmidt - * Added define for GMAC's Half Duplex Burst Mode - * Added define for Rx GMAC FIFO Flush Mask (default) - * - * Revision 1.42 2002/11/12 16:48:19 rschmidt - * Added defines for Cable Diagnostic Register (GPHY) - * Editorial changes - * - * Revision 1.41 2002/10/21 11:20:22 rschmidt - * Added bit GMR_FS_GOOD_FC to GMR_FS_ANY_ERR - * Editorial changes - * - * Revision 1.40 2002/10/14 14:54:14 rschmidt - * Added defines for GPHY Specific Status and GPHY Interrupt Status - * Added bits PHY_M_IS_AN_ERROR and PHY_M_IS_FIFO_ERROR to PHY_M_DEF_MSK - * Editorial changes - * - * Revision 1.39 2002/10/10 15:53:44 mkarl - * added some bit definitions for link speed status and LED's - * - * Revision 1.38 2002/08/21 16:23:46 rschmidt - * Added defines for PHY Specific Ctrl Reg - * Editorial changes - * - * Revision 1.37 2002/08/16 14:50:33 rschmidt - * Added defines for Auto-Neg. Advertisement YUKON Fiber (88E1011S only) - * Changed define PHY_M_DEF_MSK for GPHY IRQ Mask - * Editorial changes - * - * Revision 1.36 2002/08/12 13:21:10 rschmidt - * Added defines for different Broadcom PHY Ids - * - * Revision 1.35 2002/08/08 15:58:01 rschmidt - * Added defines for Manual LED Override register (YUKON) - * Editorial changes - * - * Revision 1.34 2002/07/31 17:23:36 rwahl - * Added define GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR). - * - * Revision 1.33 2002/07/23 16:03:37 rschmidt - * Added defines for GPHY registers - * Editorial changes - * - * Revision 1.32 2002/07/15 18:14:37 rwahl - * Added GMAC MIB counters definitions. - * Editorial changes. - * - * Revision 1.31 2002/07/15 15:42:50 rschmidt - * Removed defines from PHY specific reg. which are - * common to all PHYs - * Added defines for GMAC MIB Counters - * Editorial changes - * - * Revision 1.30 2002/06/05 08:22:12 rschmidt - * Changed defines for GMAC Rx Control Register and Rx Status - * Editorial changes - * - * Revision 1.29 2002/04/25 11:43:56 rschmidt - * Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res. - * Added new registers and defines for YUKON (GMAC, GPHY) - * Added Receive Frame Status Encoding for YUKON - * Editorial changes - * - * Revision 1.28 2000/11/09 12:32:49 rassmann - * Renamed variables. - * - * Revision 1.27 2000/05/17 11:00:46 malthoff - * Add bit for enable/disable power management in BCOM chip. - * - * Revision 1.26 1999/11/22 14:03:00 cgoos - * Changed license header to GPL. - * - * Revision 1.25 1999/08/12 19:19:38 malthoff - * Add PHY_B_AC_TX_TST bit according to BCOM A1 errata sheet. - * - * Revision 1.24 1999/07/30 11:27:21 cgoos - * Fixed a missing end-of-comment. - * - * Revision 1.23 1999/07/30 07:03:31 malthoff - * Cut some long comments. - * Correct the XMAC PHY ID definitions. - * - * Revision 1.22 1999/05/19 07:33:18 cgoos - * Changes for 1000Base-T. - * - * Revision 1.21 1999/03/25 07:46:11 malthoff - * Add XM_HW_CFG, XM_TS_READ, and XM_TS_LOAD registers. - * - * Revision 1.20 1999/03/12 13:36:09 malthoff - * Remove __STDC__. - * - * Revision 1.19 1998/12/10 12:22:54 gklug - * fix: RX_PAGE must be in interrupt mask - * - * Revision 1.18 1998/12/10 10:36:36 gklug - * fix: swap of pause bits - * - * Revision 1.17 1998/11/18 13:21:45 gklug - * fix: Default interrupt mask - * - * Revision 1.16 1998/10/29 15:53:21 gklug - * fix: Default mask uses ASS (GP0) signal - * - * Revision 1.15 1998/10/28 13:52:52 malthoff - * Add new bits in RX_CMD register. - * - * Revision 1.14 1998/10/19 15:34:53 gklug - * fix: typos - * - * Revision 1.13 1998/10/14 07:19:03 malthoff - * bug fix: Every define which describes bit 31 - * must be declared as unsigned long 'UL'. - * fix bit definitions of PHY_AN_RFB and PHY_AN_PAUSE. - * Remove ANP defines. Rework the RFB defines. - * - * Revision 1.12 1998/10/14 06:22:44 cgoos - * Changed shifted constant to ULONG. - * - * Revision 1.11 1998/10/14 05:43:26 gklug - * add: shift pause coding - * fix: PAUSE bits definition - * - * Revision 1.10 1998/10/13 09:19:21 malthoff - * Again change XMR_FS_ANY_ERR because of new info from XaQti. - * - * Revision 1.9 1998/10/09 07:58:30 malthoff - * Add XMR_FS_FCS_ERR to XMR_FS_ANY_ERR. - * - * Revision 1.8 1998/10/09 07:18:17 malthoff - * bug fix of a bug fix: XM_PAUSE_MODE and XM_DEF_MODE - * are not inverted! Bug XM_DEF_MSK is inverted. - * - * Revision 1.7 1998/10/05 08:04:32 malthoff - * bug fix: XM_PAUSE_MODE and XM_DEF_MODE - * must be inverted declarations. - * - * Revision 1.6 1998/09/28 13:38:18 malthoff - * Add default modes and masks XM_DEF_MSK, - * XM_PAUSE_MODE and XM_DEF_MODE - * - * Revision 1.5 1998/09/16 14:42:04 malthoff - * Bug Fix: XM_GP_PORT is a 32 bit (not a 16 bit) register. - * - * Revision 1.4 1998/08/20 14:59:47 malthoff - * Rework this file after reading the XaQti data sheet - * "Differences between Rev. B2 & Rev. C XMAC II". - * This file is now 100% XMAC II Rev. C complained. - * - * Revision 1.3 1998/06/29 12:18:23 malthoff - * Correct XMR_FS_ANY_ERR definition. - * - * Revision 1.2 1998/06/29 12:10:56 malthoff - * Add define XMR_FS_ANY_ERR. - * - * Revision 1.1 1998/06/19 13:37:17 malthoff - * created. - * - * - ******************************************************************************/ - #ifndef __INC_XMAC_H #define __INC_XMAC_H diff -urN linux-2.4.25/drivers/net/sk98lin/skaddr.c linux-2.4.26/drivers/net/sk98lin/skaddr.c --- linux-2.4.25/drivers/net/sk98lin/skaddr.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skaddr.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skaddr.c * Project: Gigabit Ethernet Adapters, ADDR-Module - * Version: $Revision: 1.52 $ - * Date: $Date: 2003/06/02 13:46:15 $ * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. * ******************************************************************************/ @@ -24,203 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skaddr.c,v $ - * Revision 1.52 2003/06/02 13:46:15 tschilli - * Editorial changes. - * - * Revision 1.51 2003/05/13 17:12:43 mkarl - * Changes for SLIM Driver via SK_SLIM. - * Changes for driver not using RLMT via SK_NO_RLMT. - * Changes for driver not supporting MAC address override via SK_NO_MAO. - * Separeted GENESIS and YUKON only code to reduce code size. - * Editorial changes. - * - * Revision 1.50 2003/05/08 12:29:31 rschmidt - * Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis. - * Changed initialisation for Next0[SK_MAX_MACS] to avoid - * compiler errors when SK_MAX_MACS=1. - * Editorial changes. - * - * Revision 1.49 2003/04/15 09:30:51 tschilli - * Copyright messages changed. - * "#error C++ is not yet supported." removed. - * - * Revision 1.48 2003/02/12 17:09:37 tschilli - * Fix in SkAddrOverride() to set both (physical and logical) MAC addresses - * in case that both addresses are identical. - * - * Revision 1.47 2002/09/17 06:31:10 tschilli - * Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate() - * and SkAddrGmacPromiscuousChange() fixed. - * Editorial changes. - * - * Revision 1.46 2002/08/22 07:55:41 tschilli - * New function SkGmacMcHash() for GMAC multicast hashing algorithm added. - * Editorial changes. - * - * Revision 1.45 2002/08/15 12:29:35 tschilli - * SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed. - * - * Revision 1.44 2002/08/14 12:18:03 rschmidt - * Replaced direct handling of MAC Hashing (XMAC and GMAC) - * with routine SkMacHashing(). - * Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode(). - * - * Revision 1.43 2002/08/13 09:37:43 rschmidt - * Corrected some SK_DBG_MSG outputs. - * Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode(). - * Editorial changes. - * - * Revision 1.42 2002/08/12 11:24:36 rschmidt - * Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit(). - * Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC) - * with routine SkMacPromiscMode(). - * Editorial changes. - * - * Revision 1.41 2002/06/10 13:52:18 tschilli - * Changes for handling YUKON. - * All changes are internally and not visible to the programmer - * using this module. - * - * Revision 1.40 2001/02/14 14:04:59 rassmann - * Editorial changes. - * - * Revision 1.39 2001/01/30 10:30:04 rassmann - * Editorial changes. - * - * Revision 1.38 2001/01/25 16:26:52 rassmann - * Ensured that logical address overrides are done on net's active port. - * - * Revision 1.37 2001/01/22 13:41:34 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.36 2000/08/07 11:10:39 rassmann - * Editorial changes. - * - * Revision 1.35 2000/05/04 09:38:41 rassmann - * Editorial changes. - * Corrected multicast address hashing. - * - * Revision 1.34 1999/11/22 13:23:44 cgoos - * Changed license header to GPL. - * - * Revision 1.33 1999/05/28 10:56:06 rassmann - * Editorial changes. - * - * Revision 1.32 1999/03/31 10:59:20 rassmann - * Returning Success instead of DupAddr if address shall be overridden - * with same value. - * - * Revision 1.31 1999/01/14 16:18:17 rassmann - * Corrected multicast initialization. - * - * Revision 1.30 1999/01/04 10:30:35 rassmann - * SkAddrOverride only possible after SK_INIT_IO phase. - * - * Revision 1.29 1998/12/29 13:13:10 rassmann - * An address override is now preserved in the SK_INIT_IO phase. - * All functions return an int now. - * Extended parameter checking. - * - * Revision 1.28 1998/12/01 11:45:53 rassmann - * Code cleanup. - * - * Revision 1.27 1998/12/01 09:22:49 rassmann - * SkAddrMcAdd and SkAddrMcUpdate returned SK_MC_FILTERING_INEXACT - * too often. - * - * Revision 1.26 1998/11/24 12:39:44 rassmann - * Reserved multicast entry for BPDU address. - * 13 multicast entries left for protocol. - * - * Revision 1.25 1998/11/17 16:54:23 rassmann - * Using exact match for up to 14 multicast addresses. - * Still receiving all multicasts if more addresses are added. - * - * Revision 1.24 1998/11/13 17:24:31 rassmann - * Changed return value of SkAddrOverride to int. - * - * Revision 1.23 1998/11/13 16:56:18 rassmann - * Added macro SK_ADDR_COMPARE. - * Changed return type of SkAddrOverride to SK_BOOL. - * - * Revision 1.22 1998/11/04 17:06:17 rassmann - * Corrected McUpdate and PromiscuousChange functions. - * - * Revision 1.21 1998/10/29 14:34:04 rassmann - * Clearing SK_ADDR struct at startup. - * - * Revision 1.20 1998/10/28 18:16:34 rassmann - * Avoiding I/Os before SK_INIT_RUN level. - * Aligning InexactFilter. - * - * Revision 1.19 1998/10/28 11:29:28 rassmann - * Programming physical address in SkAddrMcUpdate. - * Corrected programming of exact match entries. - * - * Revision 1.18 1998/10/28 10:34:48 rassmann - * Corrected reading of physical addresses. - * - * Revision 1.17 1998/10/28 10:26:13 rassmann - * Getting ports' current MAC addresses from EPROM now. - * Added debug output. - * - * Revision 1.16 1998/10/27 16:20:12 rassmann - * Reading MAC address byte by byte. - * - * Revision 1.15 1998/10/22 11:39:09 rassmann - * Corrected signed/unsigned mismatches. - * - * Revision 1.14 1998/10/19 17:12:35 rassmann - * Syntax corrections. - * - * Revision 1.13 1998/10/19 17:02:19 rassmann - * Now reading permanent MAC addresses from CRF. - * - * Revision 1.12 1998/10/15 15:15:48 rassmann - * Changed Flags Parameters from SK_U8 to int. - * Checked with lint. - * - * Revision 1.11 1998/09/24 19:15:12 rassmann - * Code cleanup. - * - * Revision 1.10 1998/09/18 20:18:54 rassmann - * Added HW access. - * Implemented swapping. - * - * Revision 1.9 1998/09/16 11:32:00 rassmann - * Including skdrv1st.h again. :( - * - * Revision 1.8 1998/09/16 11:09:34 rassmann - * Syntax corrections. - * - * Revision 1.7 1998/09/14 17:06:34 rassmann - * Minor changes. - * - * Revision 1.6 1998/09/07 08:45:41 rassmann - * Syntax corrections. - * - * Revision 1.5 1998/09/04 19:40:19 rassmann - * Interface enhancements. - * - * Revision 1.4 1998/09/04 12:14:12 rassmann - * Interface cleanup. - * - * Revision 1.3 1998/09/02 16:56:40 rassmann - * Updated interface. - * - * Revision 1.2 1998/08/27 14:26:09 rassmann - * Updated interface. - * - * Revision 1.1 1998/08/21 08:30:22 rassmann - * First public version. - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This module is intended to manage multicast addresses, address override, diff -urN linux-2.4.25/drivers/net/sk98lin/skcsum.c linux-2.4.26/drivers/net/sk98lin/skcsum.c --- linux-2.4.25/drivers/net/sk98lin/skcsum.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skcsum.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12 $ - * Date: $Date: 2003/08/20 13:55:53 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -21,63 +19,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skcsum.c,v $ - * Revision 1.12 2003/08/20 13:55:53 mschmid - * Changed notation of #ifndef SkCsCalculateChecksum to - * #ifndef SK_CS_CALCULATE_CHECKSUM - * - * Revision 1.11 2003/03/11 14:05:55 rschmidt - * Replaced memset() by macro SK_MEMSET() - * Editorial changes - * - * Revision 1.10 2002/04/11 10:02:04 rwahl - * Fix in SkCsGetSendInfo(): - * - function did not return ProtocolFlags in every case. - * - pseudo header csum calculated wrong for big endian. - * - * Revision 1.9 2001/06/13 07:42:08 gklug - * fix: NetNumber was wrong in CLEAR_STAT event - * add: check for good NetNumber in Clear STAT - * - * Revision 1.8 2001/02/06 11:15:36 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.7 2000/06/29 13:17:05 rassmann - * Corrected reception of a packet with UDP checksum == 0 (which means there - * is no UDP checksum). - * - * Revision 1.6 2000/02/21 12:35:10 cgoos - * Fixed license header comment. - * - * Revision 1.5 2000/02/21 11:05:19 cgoos - * Merged changes back to common source. - * Fixed rx path for BIG ENDIAN architecture. - * - * Revision 1.1 1999/07/26 15:28:12 mkarl - * added return SKCS_STATUS_IP_CSUM_ERROR_UDP and - * SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester - * changed from common source to windows specific source - * therefore restarting with v1.0 - * - * Revision 1.3 1999/05/10 08:39:33 mkarl - * prevent overflows in SKCS_HTON16 - * fixed a bug in pseudo header checksum calculation - * added some comments - * - * Revision 1.2 1998/10/22 11:53:28 swolf - * Now using SK_DBG_MSG. - * - * Revision 1.1 1998/09/01 15:35:41 swolf - * initial revision - * - * 13-May-1998 sw Created. - * - ******************************************************************************/ - #ifdef SK_USE_CSUM /* Check if CSUM is to be used. */ #ifndef lint diff -urN linux-2.4.25/drivers/net/sk98lin/skdim.c linux-2.4.26/drivers/net/sk98lin/skdim.c --- linux-2.4.25/drivers/net/sk98lin/skdim.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skdim.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skdim.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.5 $ - * Date: $Date: 2003/11/28 12:55:40 $ * Purpose: All functions to maintain interrupt moderation * ******************************************************************************/ @@ -24,40 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skdim.c,v $ - * Revision 1.5 2003/11/28 12:55:40 rroesler - * Fix: support for new process timing interface added - * - * Revision 1.4 2003/10/10 10:58:56 mlindner - * Fix: CPU detection under the kernel 2.6 - * - * Revision 1.3 2003/10/07 08:17:08 mlindner - * Fix: Copyright changes - * - * Revision 1.2 2003/08/21 12:35:05 mlindner - * Fix: Corrected CPU detection and compile errors on single CPU machines - * - * Revision 1.1 2003/07/18 13:39:55 rroesler - * Fix: Re-enter after CVS crash - * - * Revision 1.4 2003/07/07 09:45:47 rroesler - * Fix: Compiler warnings corrected - * - * Revision 1.3 2003/06/10 09:16:40 rroesler - * Adapt GetCurrentSystemLoad() to NOT access the kernels - * kstat-structure in kernel 2.5/2.6. This must be done - * due to a not exported symbol. Instead of evaluating the - * SystemLoad directly, the nbr of interrupts is used as - * a rough basis for the load. - * - * - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This module is intended to manage the dynamic interrupt moderation on both diff -urN linux-2.4.25/drivers/net/sk98lin/skge.c linux-2.4.26/drivers/net/sk98lin/skge.c --- linux-2.4.25/drivers/net/sk98lin/skge.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skge.c 2004-04-14 06:05:30.000000000 -0700 @@ -38,423 +38,6 @@ /****************************************************************************** * - * History: - * - * $Log: skge.c,v $ - * Revision 1.43 2004/01/29 15:47:07 mlindner - * Fix: Reset Xmac when stopping the port - * - * Revision 1.42 2003/12/12 10:05:43 mlindner - * Fix: Format of error message corrected - * - * Revision 1.41 2003/12/11 16:03:57 mlindner - * Fix: Create backup from pnmi data structure - * - * Revision 1.40 2003/12/11 12:14:48 mlindner - * Fix: Initalize Board before network configuration - * Fix: Change device names to driver name - * - * Revision 1.39 2003/12/10 08:57:38 rroesler - * Fix: Modifications regarding try_module_get() and capable() - * - * Revision 1.38 2003/12/01 17:16:50 mlindner - * Fix: Remove useless register_netdev - * - * Revision 1.37 2003/12/01 17:11:30 mlindner - * Fix: Register net device before SkGeBoardInit - * - * Revision 1.36 2003/11/28 13:04:27 rroesler - * Fix: do not print interface status in case DIAG is used - * - * Revision 1.35 2003/11/17 14:41:06 mlindner - * Fix: Endif command - * - * Revision 1.34 2003/11/17 13:29:05 mlindner - * Fix: Editorial changes - * - * Revision 1.33 2003/11/14 14:56:54 rroesler - * Fix: corrected compilation warnings kernel 2.2 - * - * Revision 1.32 2003/11/13 14:18:47 rroesler - * Fix: added latest changes regarding the use of the proc system - * - * Revision 1.31 2003/11/13 09:28:35 rroesler - * Fix: removed kernel warning 'driver changed get_stats after register' - * - * Revision 1.30 2003/11/11 13:15:27 rroesler - * Fix: use suitables kernel usage count macros when using the diag - * - * Revision 1.29 2003/11/10 09:38:26 rroesler - * Fix: restore PNMI structure backup for DIAG actions - * - * Revision 1.28 2003/11/07 17:28:45 rroesler - * Fix: Additions for the LeaveDiagMode - * - * Revision 1.27 2003/11/03 13:21:14 mlindner - * Add: SkGeBuffPad function for padding to ensure the trailing bytes exist - * - * Revision 1.26 2003/10/30 09:20:40 mlindner - * Fix: Control bit check - * - * Revision 1.25 2003/10/29 07:43:37 rroesler - * Fix: Implemented full None values handling for parameter Moderation - * - * Revision 1.24 2003/10/22 14:18:12 rroesler - * Fix: DIAG handling for DualNet cards - * - * Revision 1.23 2003/10/17 10:05:13 mlindner - * Add: New blinkmode for Morvell cards - * - * Revision 1.22 2003/10/15 12:31:25 rroesler - * Fix: Corrected bugreport #10954 (Linux System crash when using vlans) - * - * Revision 1.21 2003/10/07 12:32:28 mlindner - * Fix: Editorial changes - * - * Revision 1.20 2003/10/07 12:22:40 mlindner - * Fix: Compiler warnings - * - * Revision 1.19 2003/10/07 09:33:40 mlindner - * Fix: No warnings for illegal values of Mod and IntsPerSec - * Fix: Speed 100 in Half Duplex not allowed for Yukon - * Fix: PrefPort=B not allowed on single NICs - * - * Revision 1.18 2003/10/07 08:17:08 mlindner - * Fix: Copyright changes - * - * Revision 1.17 2003/09/29 12:06:59 mlindner - * *** empty log message *** - * - * Revision 1.16 2003/09/23 11:07:35 mlindner - * Fix: IO-control return race condition - * Fix: Interrupt moderation value check - * - * Revision 1.15 2003/09/22 08:40:05 mlindner - * Add: Added DRIVER_FILE_NAME and DRIVER_REL_DATE - * - * Revision 1.14 2003/09/22 08:11:10 mlindner - * Add: New function for PCI initialization (SkGeInitPCI) - * Add: Yukon Plus changes (ChipID, PCI...) - * Fix: TCP and UDP Checksum calculation - * - * Revision 1.13 2003/09/01 13:30:08 rroesler - * Fix: Corrected missing defines - * - * Revision 1.12 2003/09/01 13:12:02 rroesler - * Add: Code for improved DIAG Attach/Detach interface - * - * Revision 1.11 2003/08/26 16:05:19 mlindner - * Fix: Compiler warnings (void *) - * - * Revision 1.10 2003/08/25 09:24:08 mlindner - * Add: Dynamic Interrupt Moderation (DIM) port up message - * - * Revision 1.9 2003/08/21 14:09:43 mlindner - * Fix: Disable Half Duplex with Gigabit-Speed (Yukon). Enable Full Duplex. - * - * Revision 1.8 2003/08/19 15:09:18 mlindner - * Fix: Ignore ConType parameter if empty value - * - * Revision 1.7 2003/08/13 12:00:35 mlindner - * Fix: Removed useless defines - * - * Revision 1.6 2003/08/12 16:49:41 mlindner - * Fix: UDP and TCP HW-CSum calculation (Kernel 2.5/2.6) - * Fix: UDP and TCP Proto checks - * Fix: Build without ProcFS - * Fix: Kernel 2.6 editorial changes - * - * Revision 1.5 2003/08/07 12:25:07 mlindner - * Fix: ConType parameter check and error detection - * Fix: Insert various fixes applied to the kernel tree - * - * Revision 1.4 2003/08/07 10:50:21 mlindner - * Add: Speed and HW-Csum support for Yukon Lite chipset - * - * Revision 1.3 2003/08/06 11:24:08 mlindner - * Add: Kernel updates - * - * Revision 1.2 2003/07/21 08:28:47 rroesler - * Fix: Handle padded bytes using skb_put() - * - * Revision 1.63 2003/07/15 09:26:23 rroesler - * Fix: Removed memory leak when sending short padded frames - * - * Revision 1.62 2003/07/09 11:11:16 rroesler - * Fix: Call of ReceiveIrq() performed with parameter SK_FALSE in - * order not to hang the system with multiple spinlocks - * - * Revision 1.61 2003/07/08 07:32:41 rroesler - * Fix: Correct Kernel-version - * - * Revision 1.60 2003/07/07 15:42:30 rroesler - * Fix: Removed function pci_present() for 2.5/2.6 kernels (deprecated) - * Fix: Corrected warning in GetConfiguration() - * - * Revision 1.59 2003/07/07 09:44:32 rroesler - * Add: HW checksumming on kernel 2.5/2.6 - * Add: padding of short frames (<60 bytes) with 0x00 instead of 0xaa - * Add: ConType parameter combining multiple other parameters into one - * Fix: Corrected bugreport #10721 (warning when changing MTU size) - * Fix: Removed obsolete function SetQueueSize() - * Fix: Function ChangeMtuSize() returns new MTU size in kernel 2.5/2.6 - * - * Revision 1.58 2003/06/17 07:14:29 mlindner - * Add: Disable checksum functionality - * Fix: Unload module (Kernel 2.5) - * - * Revision 1.57 2003/06/05 14:55:27 mlindner - * Fix: ProcFS creation (Kernel 2.2.x) - * Fix: ProcFS OWNER (Kernel 2.2.x) - * - * Revision 1.56 2003/06/03 14:34:29 mlindner - * Add: Additions for SK_SLIM - * Fix: SkGeIoctl SK_IOCTL_GEN - * - * Revision 1.55 2003/05/26 13:00:52 mlindner - * Add: Support for Kernel 2.5/2.6 - * Add: Support for new IO-control MIB data structure - * Add: New SkOsGetTime function - * Fix: Race condition with broken LM80 chip - * Fix: Race condition with padded frames - * - * Revision 1.54 2003/04/28 13:07:27 mlindner - * Fix: Delay race condition with some server machines - * - * Revision 1.53 2003/04/28 12:49:49 mlindner - * Fix: Code optimization - * - * Revision 1.52 2003/04/28 12:24:32 mlindner - * Fix: Disabled HW Error IRQ on 32-bit Yukon if sensor IRQ occurs - * - * Revision 1.51 2003/04/16 08:31:14 mlindner - * Fix: Kernel 2.2 compilation - * - * Revision 1.49 2003/04/10 09:08:51 mlindner - * Add: Blink mode verification - * Fix: Checksum calculation - * - * Revision 1.48 2003/03/21 14:48:38 rroesler - * Added code for interrupt moderation - * - * Revision 1.47 2003/03/12 13:56:15 mlindner - * Fix: Mac update during SK_DRV_NET_UP - * - * Revision 1.46 2003/02/25 14:16:36 mlindner - * Fix: Copyright statement - * - * Revision 1.45 2003/02/25 13:25:55 mlindner - * Add: Performance improvements - * Add: Support for various vendors - * Fix: Init function - * - * Revision 1.44 2003/01/09 09:25:26 mlindner - * Fix: Remove useless init_module/cleanup_module forward declarations - * - * Revision 1.43 2002/11/29 08:42:41 mlindner - * Fix: Boot message - * - * Revision 1.42 2002/11/28 13:30:23 mlindner - * Add: New frame check - * - * Revision 1.41 2002/11/27 13:55:18 mlindner - * Fix: Drop wrong csum packets - * Fix: Initialize proc_entry after hw check - * - * Revision 1.40 2002/10/31 07:50:37 tschilli - * Function SkGeInitAssignRamToQueues() from common module inserted. - * Autonegotiation is set to ON for all adapters. - * LinkSpeedUsed is used in link up status report. - * Role parameter will show up for 1000 Mbps links only. - * GetConfiguration() inserted after init level 1 in SkGeChangeMtu(). - * All return values of SkGeInit() and SkGeInitPort() are checked. - * - * Revision 1.39 2002/10/02 12:56:05 mlindner - * Add: Support for Yukon - * Add: Support for ZEROCOPY, scatter-gather and hw checksum - * Add: New transmit ring function (use SG and TCP/UDP hardware checksumming) - * Add: New init function - * Add: Speed check and setup - * Add: Merge source for kernel 2.2.x and 2.4.x - * Add: Opcode check for tcp - * Add: Frame length check - * Fix: Transmit complete interrupt - * Fix: Interrupt moderation - * - * Revision 1.29.2.13 2002/01/14 12:44:52 mlindner - * Fix: Rlmt modes - * - * Revision 1.29.2.12 2001/12/07 12:06:18 mlindner - * Fix: malloc -> slab changes - * - * Revision 1.29.2.11 2001/12/06 15:19:20 mlindner - * Add: DMA attributes - * Fix: Module initialisation - * Fix: pci_map_single and pci_unmap_single replaced - * - * Revision 1.29.2.10 2001/12/06 09:56:50 mlindner - * Corrected some printk's - * - * Revision 1.29.2.9 2001/09/05 12:15:34 mlindner - * Add: LBFO Changes - * Fix: Counter Errors (Jumbo == to long errors) - * Fix: Changed pAC->PciDev declaration - * Fix: too short counters - * - * Revision 1.29.2.8 2001/06/25 12:10:44 mlindner - * fix: ReceiveIrq() changed. - * - * Revision 1.29.2.7 2001/06/25 08:07:05 mlindner - * fix: RLMT locking in ReceiveIrq() changed. - * - * Revision 1.29.2.6 2001/05/21 07:59:29 mlindner - * fix: MTU init problems - * - * Revision 1.29.2.5 2001/05/08 11:25:08 mlindner - * fix: removed VLAN error message - * - * Revision 1.29.2.4 2001/05/04 13:31:43 gklug - * fix: do not handle eth_copy on bad fragments received. - * - * Revision 1.29.2.3 2001/04/23 08:06:43 mlindner - * Fix: error handling - * - * Revision 1.29.2.2 2001/03/15 12:04:54 mlindner - * Fixed memory problem - * - * Revision 1.29.2.1 2001/03/12 16:41:44 mlindner - * add: procfs function - * add: dual-net function - * add: RLMT networks - * add: extended PNMI features - * - * Kernel 2.4.x specific: - * Revision 1.xx 2000/09/12 13:31:56 cgoos - * Fixed missign "dev=NULL in skge_probe. - * Added counting for jumbo frames (corrects error statistic). - * Removed VLAN tag check (enables VLAN support). - * - * Kernel 2.2.x specific: - * Revision 1.29 2000/02/21 13:31:56 cgoos - * Fixed "unused" warning for UltraSPARC change. - * - * Partially kernel 2.2.x specific: - * Revision 1.28 2000/02/21 10:32:36 cgoos - * Added fixes for UltraSPARC. - * Now printing RlmtMode and PrefPort setting at startup. - * Changed XmitFrame return value. - * Fixed rx checksum calculation for BIG ENDIAN systems. - * Fixed rx jumbo frames counted as ierrors. - * - * - * Revision 1.27 1999/11/25 09:06:28 cgoos - * Changed base_addr to unsigned long. - * - * Revision 1.26 1999/11/22 13:29:16 cgoos - * Changed license header to GPL. - * Changes for inclusion in linux kernel (2.2.13). - * Removed 2.0.x defines. - * Changed SkGeProbe to skge_probe. - * Added checks in SkGeIoctl. - * - * Revision 1.25 1999/10/07 14:47:52 cgoos - * Changed 984x to 98xx. - * - * Revision 1.24 1999/09/30 07:21:01 cgoos - * Removed SK_RLMT_SLOW_LOOKAHEAD option. - * Giving spanning tree packets also to OS now. - * - * Revision 1.23 1999/09/29 07:36:50 cgoos - * Changed assignment for IsBc/IsMc. - * - * Revision 1.22 1999/09/28 12:57:09 cgoos - * Added CheckQueue also to Single-Port-ISR. - * - * Revision 1.21 1999/09/28 12:42:41 cgoos - * Changed parameter strings for RlmtMode. - * - * Revision 1.20 1999/09/28 12:37:57 cgoos - * Added CheckQueue for fast delivery of RLMT frames. - * - * Revision 1.19 1999/09/16 07:57:25 cgoos - * Copperfield changes. - * - * Revision 1.18 1999/09/03 13:06:30 cgoos - * Fixed RlmtMode=CheckSeg bug: wrong DEV_KFREE_SKB in RLMT_SEND caused - * double allocated skb's. - * FrameStat in ReceiveIrq was accessed via wrong Rxd. - * Queue size for async. standby Tx queue was zero. - * FillRxLimit of 0 could cause problems with ReQueue, changed to 1. - * Removed debug output of checksum statistic. - * - * Revision 1.17 1999/08/11 13:55:27 cgoos - * Transmit descriptor polling was not reenabled after SkGePortInit. - * - * Revision 1.16 1999/07/27 15:17:29 cgoos - * Added some "\n" in output strings (removed while debuging...). - * - * Revision 1.15 1999/07/23 12:09:30 cgoos - * Performance optimization, rx checksumming, large frame support. - * - * Revision 1.14 1999/07/14 11:26:27 cgoos - * Removed Link LED settings (now in RLMT). - * Added status output at NET UP. - * Fixed SMP problems with Tx and SWITCH running in parallel. - * Fixed return code problem at RLMT_SEND event. - * - * Revision 1.13 1999/04/07 10:11:42 cgoos - * Fixed Single Port problems. - * Fixed Multi-Adapter problems. - * Always display startup string. - * - * Revision 1.12 1999/03/29 12:26:37 cgoos - * Reversed locking to fine granularity. - * Fixed skb double alloc problem (caused by incorrect xmit return code). - * Enhanced function descriptions. - * - * Revision 1.11 1999/03/15 13:10:51 cgoos - * Changed device identifier in output string to ethX. - * - * Revision 1.10 1999/03/15 12:12:34 cgoos - * Changed copyright notice. - * - * Revision 1.9 1999/03/15 12:10:17 cgoos - * Changed locking to one driver lock. - * Added check of SK_AC-size (for consistency with library). - * - * Revision 1.8 1999/03/08 11:44:02 cgoos - * Fixed missing dev->tbusy in SkGeXmit. - * Changed large frame (jumbo) buffer number. - * Added copying of short frames. - * - * Revision 1.7 1999/03/04 13:26:57 cgoos - * Fixed spinlock calls for SMP. - * - * Revision 1.6 1999/03/02 09:53:51 cgoos - * Added descriptor revertion for big endian machines. - * - * Revision 1.5 1999/03/01 08:50:59 cgoos - * Fixed SkGeChangeMtu. - * Fixed pci config space accesses. - * - * Revision 1.4 1999/02/18 15:48:44 cgoos - * Corrected some printk's. - * - * Revision 1.3 1999/02/18 12:45:55 cgoos - * Changed SK_MAX_CARD_PARAM to default 16 - * - * Revision 1.2 1999/02/18 10:55:32 cgoos - * Removed SkGeDrvTimeStamp function. - * Printing "ethX:" before adapter type at adapter init. - * - * - * 10-Feb-1999 cg Created, based on Linux' acenic.c, 3c59x.c and - * SysKonnects GEnesis Solaris driver - * - ******************************************************************************/ - -/****************************************************************************** - * * Possible compiler options (#define xxx / -Dxxx): * * debugging can be enable by changing SK_DEBUG_CHKMOD and diff -urN linux-2.4.25/drivers/net/sk98lin/skgehwt.c linux-2.4.26/drivers/net/sk98lin/skgehwt.c --- linux-2.4.25/drivers/net/sk98lin/skgehwt.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skgehwt.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgehwt.c * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.15 $ - * Date: $Date: 2003/09/16 13:41:23 $ * Purpose: Hardware Timer * ******************************************************************************/ @@ -22,60 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgehwt.c,v $ - * Revision 1.15 2003/09/16 13:41:23 rschmidt - * Added (C) Marvell to SysKonnectFileId - * Editorial changes - * - * Revision 1.14 2003/05/13 18:01:58 mkarl - * Editorial changes. - * - * Revision 1.13 1999/11/22 13:31:12 cgoos - * Changed license header to GPL. - * - * Revision 1.12 1998/10/15 15:11:34 gklug - * fix: ID_sccs to SysKonnectFileId - * - * Revision 1.11 1998/10/08 15:27:51 gklug - * chg: correction factor is host clock dependent - * - * Revision 1.10 1998/09/15 14:18:31 cgoos - * Changed more BOOLEANs to SK_xxx - * - * Revision 1.9 1998/09/15 14:16:06 cgoos - * Changed line 107: FALSE to SK_FALSE - * - * Revision 1.8 1998/08/24 13:04:44 gklug - * fix: typo - * - * Revision 1.7 1998/08/19 09:50:49 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs - * - * Revision 1.6 1998/08/17 09:59:02 gklug - * fix: typos - * - * Revision 1.5 1998/08/14 07:09:10 gklug - * fix: chg pAc -> pAC - * - * Revision 1.4 1998/08/10 14:14:52 gklug - * rmv: unneccessary SK_ADDR macro - * - * Revision 1.3 1998/08/07 12:53:44 gklug - * fix: first compiled version - * - * Revision 1.2 1998/08/07 09:19:29 gklug - * adapt functions to the C coding conventions - * rmv unneccessary functions. - * - * Revision 1.1 1998/08/05 11:28:36 gklug - * first version: adapted from SMT/FDDI - * - ******************************************************************************/ - /* * Event queue and dispatcher */ diff -urN linux-2.4.25/drivers/net/sk98lin/skgeinit.c linux-2.4.26/drivers/net/sk98lin/skgeinit.c --- linux-2.4.25/drivers/net/sk98lin/skgeinit.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skgeinit.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgeinit.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.97 $ - * Date: $Date: 2003/10/02 16:45:31 $ * Purpose: Contains functions to initialize the adapter * ******************************************************************************/ @@ -22,446 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgeinit.c,v $ - * Revision 1.97 2003/10/02 16:45:31 rschmidt - * Replaced default values of GMAC parameters with defines. - * Removed hard reset of MACs in SkGeDeInit(). - * Added define SK_PHY_LP_MODE around power saving mode in SkGeDeInit(). - * Added check for VAUX available before switch power to VAUX. - * - * Revision 1.96 2003/09/18 14:02:41 rroesler - * Add: Perform a hardreset of MACs in GeDeInit() - * - * Revision 1.95 2003/09/16 14:26:59 rschmidt - * Added switch power to VCC (WA for VAUX problem) in SkGeInit1(). - * Fixed setting PHY to coma mode and D3 power state in SkGeDeInit(). - * Editorial changes. - * - * Revision 1.94 2003/09/16 07:17:10 mschmid - * Added init for new members in port structure for MAC control - * - PMacColThres - * - PMacJamLen - * - PMacJamIpgVal - * - PMacJamIpgData - * - PMacIpgData - * - PMacLimit4 - * Added init for PHY power state in port structure - * - PPhyPowerState - * Added shutdown handling for Yukon Plus in SkGeDeInit() - * - * Revision 1.93 2003/05/28 15:44:43 rschmidt - * Added check for chip Id on WOL WA for chip Rev. A. - * Added setting of GILevel in SkGeDeInit(). - * Minor changes to avoid LINT warnings. - * Editorial changes. - * - * Revision 1.92 2003/05/13 17:42:26 mkarl - * Added SK_FAR for PXE. - * Separated code pathes not used for SLIM driver to reduce code size. - * Removed calls to I2C for SLIM driver. - * Removed currently unused function SkGeLoadLnkSyncCnt. - * Editorial changes. - * - * Revision 1.91 2003/05/06 12:21:48 rschmidt - * Added use of pAC->GIni.GIYukon for selection of YUKON branches. - * Added defines around GENESIS resp. YUKON branches to reduce - * code size for PXE. - * Editorial changes. - * - * Revision 1.90 2003/04/28 09:12:20 rschmidt - * Added init for GIValIrqMask (common IRQ mask). - * Disabled HW Error IRQ on Yukon if sensor IRQ is set in SkGeInit1() - * by changing the common mask stored in GIValIrqMask. - * Editorial changes. - * - * Revision 1.89 2003/04/10 14:33:10 rschmidt - * Fixed alignement error of patchable configuration parameter - * in struct OemConfig caused by length of recognition string. - * - * Revision 1.88 2003/04/09 12:59:45 rschmidt - * Added define around initialization of patchable OEM specific - * configuration parameter. - * - * Revision 1.87 2003/04/08 16:46:13 rschmidt - * Added configuration variable for OEMs and initialization for - * GILedBlinkCtrl (LED Blink Control). - * Improved detection for YUKON-Lite Rev. A1. - * Editorial changes. - * - * Revision 1.86 2003/03/31 06:53:13 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.85 2003/02/05 15:30:33 rschmidt - * Corrected setting of GIHstClkFact (Host Clock Factor) and - * GIPollTimerVal (Descr. Poll Timer Init Value) for YUKON. - * Editorial changes. - * - * Revision 1.84 2003/01/28 09:57:25 rschmidt - * Added detection of YUKON-Lite Rev. A0 (stored in GIYukonLite). - * Disabled Rx GMAC FIFO Flush for YUKON-Lite Rev. A0. - * Added support for CLK_RUN (YUKON-Lite). - * Added additional check of PME from D3cold for setting GIVauxAvail. - * Editorial changes. - * - * Revision 1.83 2002/12/17 16:15:41 rschmidt - * Added default setting of PhyType (Copper) for YUKON. - * Added define around check for HW self test results. - * Editorial changes. - * - * Revision 1.82 2002/12/05 13:40:21 rschmidt - * Added setting of Rx GMAC FIFO Flush Mask register. - * Corrected PhyType with new define SK_PHY_MARV_FIBER when - * YUKON Fiber board was found. - * Editorial changes. - * - * Revision 1.81 2002/11/15 12:48:35 rschmidt - * Replaced message SKERR_HWI_E018 with SKERR_HWI_E024 for Rx queue error - * in SkGeStopPort(). - * Added init for pAC->GIni.GIGenesis with SK_FALSE in YUKON-branch. - * Editorial changes. - * - * Revision 1.80 2002/11/12 17:28:30 rschmidt - * Initialized GIPciSlot64 and GIPciClock66 in SkGeInit1(). - * Reduced PCI FIFO watermarks for 32bit/33MHz bus in SkGeInitBmu(). - * Editorial changes. - * - * Revision 1.79 2002/10/21 09:31:02 mkarl - * Changed SkGeInitAssignRamToQueues(), removed call to - * SkGeInitAssignRamToQueues in SkGeInit1 and fixed compiler warning in - * SkGeInit1. - * - * Revision 1.78 2002/10/16 15:55:07 mkarl - * Fixed a bug in SkGeInitAssignRamToQueues. - * - * Revision 1.77 2002/10/14 15:07:22 rschmidt - * Corrected timeout handling for Rx queue in SkGeStopPort() (#10748) - * Editorial changes. - * - * Revision 1.76 2002/10/11 09:24:38 mkarl - * Added check for HW self test results. - * - * Revision 1.75 2002/10/09 16:56:44 mkarl - * Now call SkGeInitAssignRamToQueues() in Init Level 1 in order to assign - * the adapter memory to the queues. This default assignment is not suitable - * for dual net mode. - * - * Revision 1.74 2002/09/12 08:45:06 rwahl - * Set defaults for PMSCap, PLinkSpeed & PLinkSpeedCap dependent on PHY. - * - * Revision 1.73 2002/08/16 15:19:45 rschmidt - * Corrected check for Tx queues in SkGeCheckQSize(). - * Added init for new entry GIGenesis and GICopperType - * Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis. - * Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros. - * - * Revision 1.72 2002/08/12 13:38:55 rschmidt - * Added check if VAUX is available (stored in GIVauxAvail) - * Initialized PLinkSpeedCap in Port struct with SK_LSPEED_CAP_1000MBPS - * Editorial changes. - * - * Revision 1.71 2002/08/08 16:32:58 rschmidt - * Added check for Tx queues in SkGeCheckQSize(). - * Added start of Time Stamp Timer (YUKON) in SkGeInit2(). - * Editorial changes. - * - * Revision 1.70 2002/07/23 16:04:26 rschmidt - * Added init for GIWolOffs (HW-Bug in YUKON 1st rev.) - * Minor changes - * - * Revision 1.69 2002/07/17 17:07:08 rwahl - * - SkGeInit1(): fixed PHY type debug output; corrected init of GIFunc - * table & GIMacType. - * - Editorial changes. - * - * Revision 1.68 2002/07/15 18:38:31 rwahl - * Added initialization for MAC type dependent function table. - * - * Revision 1.67 2002/07/15 15:45:39 rschmidt - * Added Tx Store & Forward for YUKON (GMAC Tx FIFO is only 1 kB) - * Replaced SK_PHY_MARV by SK_PHY_MARV_COPPER - * Editorial changes - * - * Revision 1.66 2002/06/10 09:35:08 rschmidt - * Replaced C++ comments (//) - * Editorial changes - * - * Revision 1.65 2002/06/05 08:33:37 rschmidt - * Changed GIRamSize and Reset sequence for YUKON. - * SkMacInit() replaced by SkXmInitMac() resp. SkGmInitMac() - * - * Revision 1.64 2002/04/25 13:03:20 rschmidt - * Changes for handling YUKON. - * Removed reference to xmac_ii.h (not necessary). - * Moved all defines into header file. - * Replaced all SkXm...() functions with SkMac...() to handle also - * YUKON's GMAC. - * Added handling for GMAC FIFO in SkGeInitMacFifo(), SkGeStopPort(). - * Removed 'goto'-directive from SkGeCfgSync(), SkGeCheckQSize(). - * Replaced all XMAC-access macros by functions: SkMacRxTxDisable(), - * SkMacFlushTxFifo(). - * Optimized timeout handling in SkGeStopPort(). - * Initialized PLinkSpeed in Port struct with SK_LSPEED_AUTO. - * Release of GMAC Link Control reset in SkGeInit1(). - * Initialized GIChipId and GIChipRev in GE Init structure. - * Added GIRamSize and PhyType values for YUKON. - * Removed use of PRxCmd to setup XMAC. - * Moved setting of XM_RX_DIS_CEXT to SkXmInitMac(). - * Use of SkGeXmitLED() only for GENESIS. - * Changes for V-CPU support. - * Editorial changes. - * - * Revision 1.63 2001/04/05 11:02:09 rassmann - * Stop Port check of the STOP bit did not take 2/18 sec as wanted. - * - * Revision 1.62 2001/02/07 07:54:21 rassmann - * Corrected copyright. - * - * Revision 1.61 2001/01/31 15:31:40 gklug - * fix: problem with autosensing an SR8800 switch - * - * Revision 1.60 2000/10/18 12:22:21 cgoos - * Added workaround for half duplex hangup. - * - * Revision 1.59 2000/10/10 11:22:06 gklug - * add: in manual half duplex mode ignore carrier extension errors - * - * Revision 1.58 2000/10/02 14:10:27 rassmann - * Reading BCOM PHY after releasing reset until it returns a valid value. - * - * Revision 1.57 2000/08/03 14:55:28 rassmann - * Waiting for I2C to be ready before de-initializing adapter - * (prevents sensors from hanging up). - * - * Revision 1.56 2000/07/27 12:16:48 gklug - * fix: Stop Port check of the STOP bit does now take 2/18 sec as wanted - * - * Revision 1.55 1999/11/22 13:32:26 cgoos - * Changed license header to GPL. - * - * Revision 1.54 1999/10/26 07:32:54 malthoff - * Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics. - * - * Revision 1.53 1999/08/12 19:13:50 malthoff - * Fix for 1000BT. Do not owerwrite XM_MMU_CMD when - * disabling receiver and transmitter. Other bits - * may be lost. - * - * Revision 1.52 1999/07/01 09:29:54 gklug - * fix: DoInitRamQueue needs pAC - * - * Revision 1.51 1999/07/01 08:42:21 gklug - * chg: use Store & forward for RAM buffer when Jumbos are used - * - * Revision 1.50 1999/05/27 13:19:38 cgoos - * Added Tx PCI watermark initialization. - * Removed Tx RAM queue Store & Forward setting. - * - * Revision 1.49 1999/05/20 14:32:45 malthoff - * SkGeLinkLED() is completly removed now. - * - * Revision 1.48 1999/05/19 07:28:24 cgoos - * SkGeLinkLED no more available for drivers. - * Changes for 1000Base-T. - * - * Revision 1.47 1999/04/08 13:57:45 gklug - * add: Init of new port struct fiels PLinkResCt - * chg: StopPort Timer check - * - * Revision 1.46 1999/03/25 07:42:15 malthoff - * SkGeStopPort(): Add workaround for cache incoherency. - * Create error log entry, disable port, and - * exit loop if it does not terminate. - * Add XM_RX_LENERR_OK to the default value for the - * XMAC receive command register. - * - * Revision 1.45 1999/03/12 16:24:47 malthoff - * Remove PPollRxD and PPollTxD. - * Add check for GIPollTimerVal. - * - * Revision 1.44 1999/03/12 13:40:23 malthoff - * Fix: SkGeXmitLED(), SK_LED_TST mode does not work. - * Add: Jumbo frame support. - * Chg: Resolution of parameter IntTime in SkGeCfgSync(). - * - * Revision 1.43 1999/02/09 10:29:46 malthoff - * Bugfix: The previous modification again also for the second location. - * - * Revision 1.42 1999/02/09 09:35:16 malthoff - * Bugfix: The bits '66 MHz Capable' and 'NEWCAP are reset while - * clearing the error bits in the PCI status register. - * - * Revision 1.41 1999/01/18 13:07:02 malthoff - * Bugfix: Do not use CFG cycles after during Init- or Runtime, because - * they may not be available after Boottime. - * - * Revision 1.40 1999/01/11 12:40:49 malthoff - * Bug fix: PCI_STATUS: clearing error bits sets the UDF bit. - * - * Revision 1.39 1998/12/11 15:17:33 gklug - * chg: Init LipaAutoNeg with Unknown - * - * Revision 1.38 1998/12/10 11:02:57 malthoff - * Disable Error Log Message when calling SkGeInit(level 2) - * more than once. - * - * Revision 1.37 1998/12/07 12:18:25 gklug - * add: refinement of autosense mode: take into account the autoneg cap of LiPa - * - * Revision 1.36 1998/12/07 07:10:39 gklug - * fix: init values of LinkBroken/ Capabilities for management - * - * Revision 1.35 1998/12/02 10:56:20 gklug - * fix: do NOT init LoinkSync Counter. - * - * Revision 1.34 1998/12/01 10:53:21 gklug - * add: init of additional Counters for workaround - * - * Revision 1.33 1998/12/01 10:00:49 gklug - * add: init PIsave var in Port struct - * - * Revision 1.32 1998/11/26 14:50:40 gklug - * chg: Default is autosensing with AUTOFULL mode - * - * Revision 1.31 1998/11/25 15:36:16 gklug - * fix: do NOT stop LED Timer when port should be stopped - * - * Revision 1.30 1998/11/24 13:15:28 gklug - * add: Init PCkeckPar struct member - * - * Revision 1.29 1998/11/18 13:19:27 malthoff - * Disable packet arbiter timeouts on receive side. - * Use maximum timeout value for packet arbiter - * transmit timeouts. - * Add TestStopBit() function to handle stop RX/TX - * problem with active descriptor poll timers. - * Bug Fix: Descriptor Poll Timer not started, because - * GIPollTimerVal was initialized with 0. - * - * Revision 1.28 1998/11/13 14:24:26 malthoff - * Bug Fix: SkGeStopPort() may hang if a Packet Arbiter Timout - * is pending or occurs while waiting for TX_STOP and RX_STOP. - * The PA timeout is cleared now while waiting for TX- or RX_STOP. - * - * Revision 1.27 1998/11/02 11:04:36 malthoff - * fix the last fix - * - * Revision 1.26 1998/11/02 10:37:03 malthoff - * Fix: SkGePollTxD() enables always the synchronounous poll timer. - * - * Revision 1.25 1998/10/28 07:12:43 cgoos - * Fixed "LED_STOP" in SkGeLnkSyncCnt, "== SK_INIT_IO" in SkGeInit. - * Removed: Reset of RAM Interface in SkGeStopPort. - * - * Revision 1.24 1998/10/27 08:13:12 malthoff - * Remove temporary code. - * - * Revision 1.23 1998/10/26 07:45:03 malthoff - * Add Address Calculation Workaround: If the EPROM byte - * Id is 3, the address offset is 512 kB. - * Initialize default values for PLinkMode and PFlowCtrlMode. - * - * Revision 1.22 1998/10/22 09:46:47 gklug - * fix SysKonnectFileId typo - * - * Revision 1.21 1998/10/20 12:11:56 malthoff - * Don't dendy the Queue config if the size of the unused - * Rx qeueu is zero. - * - * Revision 1.20 1998/10/19 07:27:58 malthoff - * SkGeInitRamIface() is public to be called by diagnostics. - * - * Revision 1.19 1998/10/16 13:33:45 malthoff - * Fix: enabling descriptor polling is not allowed until - * the descriptor addresses are set. Descriptor polling - * must be handled by the driver. - * - * Revision 1.18 1998/10/16 10:58:27 malthoff - * Remove temp. code for Diag prototype. - * Remove lint warning for dummy reads. - * Call SkGeLoadLnkSyncCnt() during SkGeInitPort(). - * - * Revision 1.17 1998/10/14 09:16:06 malthoff - * Change parameter LimCount and programming of - * the limit counter in SkGeCfgSync(). - * - * Revision 1.16 1998/10/13 09:21:16 malthoff - * Don't set XM_RX_SELF_RX in RxCmd Reg, because it's - * like a Loopback Mode in half duplex. - * - * Revision 1.15 1998/10/09 06:47:40 malthoff - * SkGeInitMacArb(): set recovery counters init value - * to zero although this counters are not uesd. - * Bug fix in Rx Upper/Lower Pause Threshold calculation. - * Add XM_RX_SELF_RX to RxCmd. - * - * Revision 1.14 1998/10/06 15:15:53 malthoff - * Make sure no pending IRQ is cleared in SkGeLoadLnkSyncCnt(). - * - * Revision 1.13 1998/10/06 14:09:36 malthoff - * Add SkGeLoadLnkSyncCnt(). Modify - * the 'port stopped' condition according - * to the current problem report. - * - * Revision 1.12 1998/10/05 08:17:21 malthoff - * Add functions: SkGePollRxD(), SkGePollTxD(), - * DoCalcAddr(), SkGeCheckQSize(), - * DoInitRamQueue(), and SkGeCfgSync(). - * Add coding for SkGeInitMacArb(), SkGeInitPktArb(), - * SkGeInitMacFifo(), SkGeInitRamBufs(), - * SkGeInitRamIface(), and SkGeInitBmu(). - * - * Revision 1.11 1998/09/29 08:26:29 malthoff - * bug fix: SkGeInit0() 'i' should be increment. - * - * Revision 1.10 1998/09/28 13:19:01 malthoff - * Coding time: Save the done work. - * Modify SkGeLinkLED(), add SkGeXmitLED(), - * define SkGeCheckQSize(), SkGeInitMacArb(), - * SkGeInitPktArb(), SkGeInitMacFifo(), - * SkGeInitRamBufs(), SkGeInitRamIface(), - * and SkGeInitBmu(). Do coding for SkGeStopPort(), - * SkGeInit1(), SkGeInit2(), and SkGeInit3(). - * Do coding for SkGeDinit() and SkGeInitPort(). - * - * Revision 1.9 1998/09/16 14:29:05 malthoff - * Some minor changes. - * - * Revision 1.8 1998/09/11 05:29:14 gklug - * add: init state of a port - * - * Revision 1.7 1998/09/04 09:26:25 malthoff - * Short temporary modification. - * - * Revision 1.6 1998/09/04 08:27:59 malthoff - * Remark the do-while in StopPort() because it never ends - * without a GE adapter. - * - * Revision 1.5 1998/09/03 14:05:45 malthoff - * Change comment for SkGeInitPort(). Do not - * repair the queue sizes if invalid. - * - * Revision 1.4 1998/09/03 10:03:19 malthoff - * Implement the new interface according to the - * reviewed interface specification. - * - * Revision 1.3 1998/08/19 09:11:25 gklug - * fix: struct are removed from c-source (see CCC) - * - * Revision 1.2 1998/07/28 12:33:58 malthoff - * Add 'IoC' parameter in function declaration and SK IO macros. - * - * Revision 1.1 1998/07/23 09:48:57 malthoff - * Creation. First dummy 'C' file. - * SkGeInit(Level 0) is card_start for GE. - * SkGeDeInit() is card_stop for GE. - * - * - ******************************************************************************/ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" diff -urN linux-2.4.25/drivers/net/sk98lin/skgemib.c linux-2.4.26/drivers/net/sk98lin/skgemib.c --- linux-2.4.25/drivers/net/sk98lin/skgemib.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skgemib.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgemib.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/09/15 13:38:12 $ * Purpose: Private Network Management Interface Management Database * ****************************************************************************/ @@ -22,54 +20,6 @@ * ******************************************************************************/ -/***************************************************************************** - * - * History: - * - * $Log: skgemib.c,v $ - * Revision 1.11 2003/09/15 13:38:12 tschilli - * OID_SKGE_PHY_LP_MODE included only after using #define SK_PHY_LP_MODE. - * - * Revision 1.10 2003/08/15 12:28:59 tschilli - * Added new OIDs: - * OID_SKGE_DRIVER_RELDATE - * OID_SKGE_DRIVER_FILENAME - * OID_SKGE_CHIPID - * OID_SKGE_RAMSIZE - * OID_SKGE_VAUXAVAIL - * OID_SKGE_PHY_TYPE - * OID_SKGE_PHY_LP_MODE - * - * Revision 1.9 2003/05/23 12:55:20 tschilli - * OID_SKGE_BOARDLEVEL added. - * - * Revision 1.8 2003/03/27 11:19:15 tschilli - * Copyright messages changed. - * - * Revision 1.7 2002/12/16 09:04:34 tschilli - * Code for VCT handling added. - * - * Revision 1.6 2002/08/09 15:40:21 rwahl - * Editorial change (renamed ConfSpeedCap). - * - * Revision 1.5 2002/08/09 11:05:34 rwahl - * Added oid handling for link speed cap. - * - * Revision 1.4 2002/08/09 09:40:27 rwahl - * Added support for NDIS OID_PNP_xxx. - * - * Revision 1.3 2002/07/17 19:39:54 rwahl - * Added handler for OID_SKGE_SPEED_MODE & OID_SKGE_SPEED_STATUS. - * - * Revision 1.2 2002/05/22 08:59:00 rwahl - * - static functions only for release build. - * - Source file must be included. - * - * Revision 1.1 2002/05/22 08:12:42 rwahl - * Initial version. - * - ****************************************************************************/ - /* * PRIVATE OID handler function prototypes */ diff -urN linux-2.4.25/drivers/net/sk98lin/skgepnmi.c linux-2.4.26/drivers/net/sk98lin/skgepnmi.c --- linux-2.4.25/drivers/net/sk98lin/skgepnmi.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skgepnmi.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.111 $ - * Date: $Date: 2003/09/15 13:35:35 $ * Purpose: Private Network Management Interface * ****************************************************************************/ @@ -22,469 +20,6 @@ * ******************************************************************************/ -/***************************************************************************** - * - * History: - * - * $Log: skgepnmi.c,v $ - * Revision 1.111 2003/09/15 13:35:35 tschilli - * Code for OID_SKGE_PHY_LP_MODE completed (using #define SK_PHY_LP_MODE). - * SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions() changed. - * - * Revision 1.110 2003/08/15 12:28:04 tschilli - * Added new OIDs: - * OID_SKGE_DRIVER_RELDATE - * OID_SKGE_DRIVER_FILENAME - * OID_SKGE_CHIPID - * OID_SKGE_RAMSIZE - * OID_SKGE_VAUXAVAIL - * OID_SKGE_PHY_TYPE - * OID_SKGE_PHY_LP_MODE - * - * Added SK_DIAG_ATTACHED handling for OID_SKGE_DIAG_MODE in DiagActions(). - * - * Revision 1.109 2003/07/17 14:15:24 tschilli - * Bug in SkPnmiGenIoctl() fixed. - * - * Revision 1.108 2003/05/27 07:10:11 tschilli - * Bug in SkPnmiGenIoctl() fixed. - * - * Revision 1.107 2003/05/23 13:01:10 tschilli - * Code for DIAG support added (#define SK_DIAG_SUPPORT). - * Code for generic PNMI IOCTL support added. The new function - * SkPnmiGenIoctl() is used for this purpose. - * Handling of OID_SKGE_BOARDLEVEL added. - * Incorrect buffer size handling of OID_SKGE_MTU during GET action fixed. - * Return code handling in PowerManagement() fixed. - * Editorial changes. - * - * Revision 1.106 2003/04/10 14:47:31 rschmidt - * Fixed handling for OID_GEN_RCV_OK and OID_GEN_XMIT_OK for YUKON's GMAC - * in GetPhysStatVal(). - * Replaced macro PHY_READ() with function call SkXmPhyRead(). - * Made optimisations for readability and code size. - * Editorial changes. - * - * Revision 1.105 2003/04/09 12:51:32 rschmidt - * Fixed XMAC only handling for some events in SkPnmiEvent(). - * Fixed return value for OID_GEN_RCV_OK (SK_PNMI_HRX) in GetPhysStatVal(). - * Editorial changes. - * - * Revision 1.104 2003/03/27 11:18:21 tschilli - * BRK statements from DEBUG code removed. - * OID_GEN_XMIT_OK and OID_GEN_RCV_OK work with Yukon now. - * Copyright messages changed. - * - * Revision 1.103 2002/12/20 09:57:13 tschilli - * SK_PNMI_EVT_VCT_RESET event code changed. - * Unused variable from Vct() removed. - * - * Revision 1.102 2002/12/16 14:03:24 tschilli - * VCT code in Vct() changed. - * - * Revision 1.101 2002/12/16 09:04:10 tschilli - * Code for VCT handling added. - * - * Revision 1.100 2002/09/26 14:28:13 tschilli - * For XMAC the values in the SK_PNMI_PORT Port struct are copied to - * the new SK_PNMI_PORT BufPort struct during a MacUpdate() call. - * These values are used when GetPhysStatVal() is called. With this - * mechanism you get the best results when software corrections for - * counters are needed. Example: RX_LONGFRAMES. - * - * Revision 1.99 2002/09/17 12:31:19 tschilli - * OID_SKGE_TX_HW_ERROR_CTS, OID_SKGE_OUT_ERROR_CTS, OID_GEN_XMIT_ERROR: - * Double count of SK_PNMI_HTX_EXCESS_COL in function General() removed. - * OID_PNP_CAPABILITIES: sizeof(SK_PM_WAKE_UP_CAPABILITIES) changed to - * sizeof(SK_PNP_CAPABILITIES) in function PowerManagement(). - * - * Revision 1.98 2002/09/10 09:00:03 rwahl - * Adapted boolean definitions according sktypes. - * - * Revision 1.97 2002/09/05 15:07:03 rwahl - * Editorial changes. - * - * Revision 1.96 2002/09/05 11:04:14 rwahl - * - Rx/Tx packets statistics of virtual port were zero on link down (#10750) - * - For GMAC the overflow IRQ for Rx longframe counter was not counted. - * - Incorrect calculation for oids OID_SKGE_RX_HW_ERROR_CTS, - * OID_SKGE_IN_ERRORS_CTS, OID_GEN_RCV_ERROR. - * - Moved correction for OID_SKGE_STAT_RX_TOO_LONG to GetPhysStatVal(). - * - Editorial changes. - * - * Revision 1.95 2002/09/04 08:53:37 rwahl - * - Incorrect statistics for Rx_too_long counter with jumbo frame (#10751) - * - StatRxFrameTooLong & StatRxPMaccErr counters were not reset. - * - Fixed compiler warning for debug msg arg types. - * - * Revision 1.94 2002/08/09 15:42:14 rwahl - * - Fixed StatAddr table for GMAC. - * - VirtualConf(): returned indeterminated status for speed oids if no - * active port. - * - * Revision 1.93 2002/08/09 11:04:59 rwahl - * Added handler for link speed caps. - * - * Revision 1.92 2002/08/09 09:43:03 rwahl - * - Added handler for NDIS OID_PNP_xxx ids. - * - * Revision 1.91 2002/07/17 19:53:03 rwahl - * - Added StatOvrflwBit table for XMAC & GMAC. - * - Extended StatAddr table for GMAC. Added check of number of counters - * in enumeration and size of StatAddr table on init level. - * - Added use of GIFunc table. - * - ChipSet is not static anymore, - * - Extended SIRQ event handler for both mac types. - * - Fixed rx short counter bug (#10620) - * - Added handler for oids SKGE_SPEED_MODE & SKGE_SPEED_STATUS. - * - Extended GetPhysStatVal() for GMAC. - * - Editorial changes. - * - * Revision 1.90 2002/05/22 08:56:25 rwahl - * - Moved OID table to separate source file. - * - Fix: TX_DEFFERAL counter incremented in full-duplex mode. - * - Use string definitions for error msgs. - * - * Revision 1.89 2001/09/18 10:01:30 mkunz - * some OID's fixed for dualnetmode - * - * Revision 1.88 2001/08/02 07:58:08 rwahl - * - Fixed NetIndex to csum module at ResetCounter(). - * - * Revision 1.87 2001/04/06 13:35:09 mkunz - * -Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's - * - * Revision 1.86 2001/03/09 09:18:03 mkunz - * Changes in SK_DBG_MSG - * - * Revision 1.85 2001/03/08 09:37:31 mkunz - * Bugfix in ResetCounter for Pnmi.Port structure - * - * Revision 1.84 2001/03/06 09:04:55 mkunz - * Made some changes in instance calculation - * - * Revision 1.83 2001/02/15 09:15:32 mkunz - * Necessary changes for dual net mode added - * - * Revision 1.82 2001/02/07 08:24:19 mkunz - * -Made changes in handling of OID_SKGE_MTU - * - * Revision 1.81 2001/02/06 09:58:00 mkunz - * -Vpd bug fixed - * -OID_SKGE_MTU added - * -pnmi support for dual net mode. Interface function and macros extended - * - * Revision 1.80 2001/01/22 13:41:35 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.79 2000/12/05 14:57:40 cgoos - * SetStruct failed before first Link Up (link mode of virtual - * port "INDETERMINATED"). - * - * Revision 1.78 2000/09/12 10:44:58 cgoos - * Fixed SK_PNMI_STORE_U32 calls with typecasted argument. - * - * Revision 1.77 2000/09/07 08:10:19 rwahl - * - Modified algorithm for 64bit NDIS statistic counters; - * returns 64bit or 32bit value depending on passed buffer - * size. Indicate capability for 64bit NDIS counter, if passed - * buffer size is zero. OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR, - * and OID_GEN_RCV_NO_BUFFER handled as 64bit counter, too. - * - corrected OID_SKGE_RLMT_PORT_PREFERRED. - * - * Revision 1.76 2000/08/03 15:23:39 rwahl - * - Correction for FrameTooLong counter has to be moved to OID handling - * routines (instead of statistic counter routine). - * - Fix in XMAC Reset Event handling: Only offset counter for hardware - * statistic registers are updated. - * - * Revision 1.75 2000/08/01 16:46:05 rwahl - * - Added StatRxLongFrames counter and correction of FrameTooLong counter. - * - Added directive to control width (default = 32bit) of NDIS statistic - * counters (SK_NDIS_64BIT_CTR). - * - * Revision 1.74 2000/07/04 11:41:53 rwahl - * - Added volition connector type. - * - * Revision 1.73 2000/03/15 16:33:10 rwahl - * Fixed bug 10510; wrong reset of virtual port statistic counters. - * - * Revision 1.72 1999/12/06 16:15:53 rwahl - * Fixed problem of instance range for current and factory MAC address. - * - * Revision 1.71 1999/12/06 10:14:20 rwahl - * Fixed bug 10476; set operation for PHY_OPERATION_MODE. - * - * Revision 1.70 1999/11/22 13:33:34 cgoos - * Changed license header to GPL. - * - * Revision 1.69 1999/10/18 11:42:15 rwahl - * Added typecasts for checking event dependent param (debug only). - * - * Revision 1.68 1999/10/06 09:35:59 cgoos - * Added state check to PHY_READ call (hanged if called during startup). - * - * Revision 1.67 1999/09/22 09:53:20 rwahl - * - Read Broadcom register for updating FCS error counter (1000Base-T). - * - * Revision 1.66 1999/08/26 13:47:56 rwahl - * Added SK_DRIVER_SENDEVENT when queueing RLMT_CHANGE_THRES trap. - * - * Revision 1.65 1999/07/26 07:49:35 cgoos - * Added two typecasts to avoid compiler warnings. - * - * Revision 1.64 1999/05/20 09:24:12 cgoos - * Changes for 1000Base-T (sensors, Master/Slave). - * - * Revision 1.63 1999/04/13 15:11:58 mhaveman - * Moved include of rlmt.h to header skgepnmi.h because some macros - * are needed there. - * - * Revision 1.62 1999/04/13 15:08:07 mhaveman - * Replaced again SK_RLMT_CHECK_LINK with SK_PNMI_RLMT_MODE_CHK_LINK - * to grant unified interface by only using the PNMI header file. - * SK_PNMI_RLMT_MODE_CHK_LINK is defined the same as SK_RLMT_CHECK_LINK. - * - * Revision 1.61 1999/04/13 15:02:48 mhaveman - * Changes caused by review: - * -Changed some comments - * -Removed redundant check for OID_SKGE_PHYS_FAC_ADDR - * -Optimized PRESET check. - * -Meaning of error SK_ADDR_DUPLICATE_ADDRESS changed. Set of same - * address will now not cause this error. Removed corresponding check. - * - * Revision 1.60 1999/03/23 10:41:23 mhaveman - * Added comments. - * - * Revision 1.59 1999/02/19 08:01:28 mhaveman - * Fixed bug 10372 that after counter reset all ports were displayed - * as inactive. - * - * Revision 1.58 1999/02/16 18:04:47 mhaveman - * Fixed problem of twisted OIDs SENSOR_WAR_TIME and SENSOR_ERR_TIME. - * - * Revision 1.56 1999/01/27 12:29:11 mhaveman - * SkTimerStart was called with time value in milli seconds but needs - * micro seconds. - * - * Revision 1.55 1999/01/25 15:00:38 mhaveman - * Added support to allow multiple ports to be active. If this feature in - * future will be used, the Management Data Base variables PORT_ACTIVE - * and PORT_PREFERED should be moved to the port specific part of RLMT. - * Currently they return the values of the first active physical port - * found. A set to the virtual port will actually change all active - * physical ports. A get returns the melted values of all active physical - * ports. If the port values differ a return value INDETERMINATED will - * be returned. This effects especially the CONF group. - * - * Revision 1.54 1999/01/19 10:10:22 mhaveman - * -Fixed bug 10354: Counter values of virtual port were wrong after port - * switches - * -Added check if a switch to the same port is notified. - * - * Revision 1.53 1999/01/07 09:25:21 mhaveman - * Forgot to initialize a variable. - * - * Revision 1.52 1999/01/05 10:34:33 mhaveman - * Fixed little error in RlmtChangeEstimate calculation. - * - * Revision 1.51 1999/01/05 09:59:07 mhaveman - * -Moved timer start to init level 2 - * -Redesigned port switch average calculation to avoid 64bit - * arithmetic. - * - * Revision 1.50 1998/12/10 15:13:59 mhaveman - * -Fixed: PHYS_CUR_ADDR returned wrong addresses - * -Fixed: RLMT_PORT_PREFERED and RLMT_CHANGE_THRES preset returned - * always BAD_VALUE. - * -Fixed: TRAP buffer seemed to sometimes suddenly empty - * - * Revision 1.49 1998/12/09 16:17:07 mhaveman - * Fixed: Couldnot delete VPD keys on UNIX. - * - * Revision 1.48 1998/12/09 14:11:10 mhaveman - * -Add: Debugmessage for XMAC_RESET supressed to minimize output. - * -Fixed: RlmtChangeThreshold will now be initialized. - * -Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char. - * -Fixed: On VPD key creation an invalid key name could be created - * (e.g. A5) - * -Some minor changes in comments and code. - * - * Revision 1.47 1998/12/08 16:00:31 mhaveman - * -Fixed: For RLMT_PORT_ACTIVE will now be returned a 0 if no port - * is active. - * -Fixed: For the RLMT statistics group only the last value was - * returned and the rest of the buffer was filled with 0xff - * -Fixed: Mysteriously the preset on RLMT_MODE still returned - * BAD_VALUE. - * Revision 1.46 1998/12/08 10:04:56 mhaveman - * -Fixed: Preset on RLMT_MODE returned always BAD_VALUE error. - * -Fixed: Alignment error in GetStruct - * -Fixed: If for Get/Preset/SetStruct the buffer size is equal or - * larger than SK_PNMI_MIN_STRUCT_SIZE the return value is stored - * to the buffer. In this case the caller should always return - * ok to its upper routines. Only if the buffer size is less - * than SK_PNMI_MIN_STRUCT_SIZE and the return value is unequal - * to 0, an error should be returned by the caller. - * -Fixed: Wrong number of instances with RLMT statistic. - * -Fixed: Return now SK_LMODE_STAT_UNKNOWN if the LinkModeStatus is 0. - * - * Revision 1.45 1998/12/03 17:17:24 mhaveman - * -Removed for VPD create action the buffer size limitation to 4 bytes. - * -Pass now physical/active physical port to ADDR for CUR_ADDR set - * - * Revision 1.44 1998/12/03 15:14:35 mhaveman - * Another change to Vpd instance evaluation. - * - * Revision 1.43 1998/12/03 14:18:10 mhaveman - * -Fixed problem in PnmiSetStruct. It was impossible to set any value. - * -Removed VPD key evaluation for VPD_FREE_BYTES and VPD_ACTION. - * - * Revision 1.42 1998/12/03 11:31:47 mhaveman - * Inserted cast to satisfy lint. - * - * Revision 1.41 1998/12/03 11:28:16 mhaveman - * Removed SK_PNMI_CHECKPTR - * - * Revision 1.40 1998/12/03 11:19:07 mhaveman - * Fixed problems - * -A set to virtual port will now be ignored. A set with broadcast - * address to any port will be ignored. - * -GetStruct function made VPD instance calculation wrong. - * -Prefered port returned -1 instead of 0. - * - * Revision 1.39 1998/11/26 15:30:29 mhaveman - * Added sense mode to link mode. - * - * Revision 1.38 1998/11/23 15:34:00 mhaveman - * -Fixed bug for RX counters. On an RX overflow interrupt the high - * words of all RX counters were incremented. - * -SET operations on FLOWCTRL_MODE and LINK_MODE accept now the - * value 0, which has no effect. It is usefull for multiple instance - * SETs. - * - * Revision 1.37 1998/11/20 08:02:04 mhaveman - * -Fixed: Ports were compared with MAX_SENSORS - * -Fixed: Crash in GetTrapEntry with MEMSET macro - * -Fixed: Conversions between physical, logical port index and instance - * - * Revision 1.36 1998/11/16 07:48:53 mhaveman - * Casted SK_DRIVER_SENDEVENT with (void) to eleminate compiler warnings - * on Solaris. - * - * Revision 1.35 1998/11/16 07:45:34 mhaveman - * SkAddrOverride now returns value and will be checked. - * - * Revision 1.34 1998/11/10 13:40:37 mhaveman - * Needed to change interface, because NT driver needs a return value - * of needed buffer space on TOO_SHORT errors. Therefore all - * SkPnmiGet/Preset/Set functions now have a pointer to the length - * parameter, where the needed space on error is returned. - * - * Revision 1.33 1998/11/03 13:52:46 mhaveman - * Made file lint conform. - * - * Revision 1.32 1998/11/03 13:19:07 mhaveman - * The events SK_HWEV_SET_LMODE and SK_HWEV_SET_FLOWMODE pass now in - * Para32[0] the physical MAC index and in Para32[1] the new mode. - * - * Revision 1.31 1998/11/03 12:30:40 gklug - * fix: compiler warning memset - * - * Revision 1.30 1998/11/03 12:04:46 mhaveman - * Fixed problem in SENSOR_VALUE, which wrote beyond the buffer end - * Fixed alignment problem with CHIPSET. - * - * Revision 1.29 1998/11/02 11:23:54 mhaveman - * Corrected SK_ERROR_LOG to SK_ERR_LOG. Sorry. - * - * Revision 1.28 1998/11/02 10:47:16 mhaveman - * Added syslog messages for internal errors. - * - * Revision 1.27 1998/10/30 15:48:06 mhaveman - * Fixed problems after simulation of SK_PNMI_EVT_CHG_EST_TIMER and - * RlmtChangeThreshold calculation. - * - * Revision 1.26 1998/10/29 15:36:55 mhaveman - * -Fixed bug in trap buffer handling. - * -OID_SKGE_DRIVER_DESCR, OID_SKGE_DRIVER_VERSION, OID_SKGE_HW_DESCR, - * OID_SKGE_HW_VERSION, OID_SKGE_VPD_ENTRIES_LIST, OID_SKGE_VPD_KEY, - * OID_SKGE_VPD_VALUE, and OID_SKGE_SENSOR_DESCR return values with - * a leading octet before each string storing the string length. - * -Perform a RlmtUpdate during SK_PNMI_EVT_XMAC_RESET to minimize - * RlmtUpdate calls in GetStatVal. - * -Inserted SK_PNMI_CHECKFLAGS macro increase readability. - * - * Revision 1.25 1998/10/29 08:50:36 mhaveman - * Fixed problems after second event simulation. - * - * Revision 1.24 1998/10/28 08:44:37 mhaveman - * -Fixed alignment problem - * -Fixed problems during event simulation - * -Fixed sequence of error return code (INSTANCE -> ACCESS -> SHORT) - * -Changed type of parameter Instance back to SK_U32 because of VPD - * -Updated new VPD function calls - * - * Revision 1.23 1998/10/23 10:16:37 mhaveman - * Fixed bugs after buffer test simulation. - * - * Revision 1.22 1998/10/21 13:23:52 mhaveman - * -Call syntax of SkOsGetTime() changed to SkOsGetTime(pAc). - * -Changed calculation of hundrets of seconds. - * - * Revision 1.20 1998/10/20 07:30:45 mhaveman - * Made type changes to unsigned integer where possible. - * - * Revision 1.19 1998/10/19 10:51:30 mhaveman - * -Made Bug fixes after simulation run - * -Renamed RlmtMAC... to RlmtPort... - * -Marked workarounds with Errata comments - * - * Revision 1.18 1998/10/14 07:50:08 mhaveman - * -For OID_SKGE_LINK_STATUS the link down detection has moved from RLMT - * to HWACCESS. - * -Provided all MEMCPY/MEMSET macros with (char *) pointers, because - * Solaris throwed warnings when mapping to bcopy/bset. - * - * Revision 1.17 1998/10/13 07:42:01 mhaveman - * -Added OIDs OID_SKGE_TRAP_NUMBER and OID_SKGE_ALL_DATA - * -Removed old cvs history entries - * -Renamed MacNumber to PortNumber - * - * Revision 1.16 1998/10/07 10:52:49 mhaveman - * -Inserted handling of some OID_GEN_ Ids for windows - * -Fixed problem with 803.2 statistic. - * - * Revision 1.15 1998/10/01 09:16:29 mhaveman - * Added Debug messages for function call and UpdateFlag tracing. - * - * Revision 1.14 1998/09/30 13:39:09 mhaveman - * -Reduced namings of 'MAC' by replacing them with 'PORT'. - * -Completed counting of OID_SKGE_RX_HW_ERROR_CTS, - * OID_SKGE_TX_HW_ERROR_CTS, - * OID_SKGE_IN_ERRORS_CTS, and OID_SKGE_OUT_ERROR_CTS. - * -SET check for RlmtMode - * - * Revision 1.13 1998/09/28 13:13:08 mhaveman - * Hide strcmp, strlen, and strncpy behind macros SK_STRCMP, SK_STRLEN, - * and SK_STRNCPY. (Same reasons as for mem.. and MEM..) - * - * Revision 1.12 1998/09/16 08:18:36 cgoos - * Fix: XM_INxx and XM_OUTxx called with different parameter order: - * sometimes IoC,Mac,... sometimes Mac,IoC,... Now always first variant. - * Fix: inserted "Pnmi." into some pAC->pDriverDescription / Version. - * Change: memset, memcpy to makros SK_MEMSET, SK_MEMCPY - * - * Revision 1.11 1998/09/04 17:01:45 mhaveman - * Added SyncCounter as macro and OID_SKGE_.._NO_DESCR_CTS to - * OID_SKGE_RX_NO_BUF_CTS. - * - * Revision 1.10 1998/09/04 14:35:35 mhaveman - * Added macro counters, that are counted by driver. - * - ****************************************************************************/ - - #ifndef _lint static const char SysKonnectFileId[] = "@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell."; diff -urN linux-2.4.25/drivers/net/sk98lin/skgesirq.c linux-2.4.26/drivers/net/sk98lin/skgesirq.c --- linux-2.4.25/drivers/net/sk98lin/skgesirq.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skgesirq.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skgesirq.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.92 $ - * Date: $Date: 2003/09/16 14:37:07 $ * Purpose: Special IRQ module * ******************************************************************************/ @@ -22,374 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skgesirq.c,v $ - * Revision 1.92 2003/09/16 14:37:07 rschmidt - * Added debug messages in some SkGePortCheckUp...() routines. - * Fixed compiler warnings for different types. - * Avoided port check up in reset state (eg. coma mode). - * Editorial changes. - * - * Revision 1.91 2003/07/04 12:46:22 rschmidt - * Added debug messages in SkGePortCheckUpGmac(). - * Added error log message and new driver event SK_DRV_DOWNSHIFT_DET - * for Downshift detection (Yukon-Copper). - * Editorial changes. - * - * Revision 1.90 2003/05/28 15:35:45 rschmidt - * Added parameter AutoNeg in all SkGePortCheckUp...() to save code. - * Added setting for AutoNeg only once in SkGePortCheckUp(). - * Moved defines for return codes of SkGePortCheckUp() to header file. - * Editorial changes. - * - * Revision 1.89 2003/05/13 17:32:20 mkarl - * Removed links to RLMT and PNMI for SLIM driver (SK_SLIM). - * Separated GENESIS and YUKON only code to reduce code size. - * - * Revision 1.88 2003/05/06 13:20:34 rschmidt - * Changed workaround for Tx hang in half duplex only for Genesis. - * Replaced SkPnmiGetVar() calls for Tx Octets Counter - * with SkXmMacStatistic() in SkGeSirqIsr(). - * Added defines around GENESIS resp. YUKON branches to reduce - * code size for PXE. - * Editorial changes. - * - * Revision 1.87 2003/04/28 09:18:31 rschmidt - * Added increment for GITimeStampCnt (high dword for - * Time Stamp Timer counter), when overflow IRQ occurs. - * Disabled HW Error IRQ on 32-bit Yukon if sensor IRQ occurs - * by changing the common mask stored in GIValIrqMask. - * Changed handling for HW Error IRQ in SkGeSirqIsr(). - * Added clearing of the software forced IRQ in SkGeSirqIsr(). - * Editorial changes. - * - * Revision 1.86 2003/04/09 13:03:24 rschmidt - * Added workaround for configuration of GPHY's Auto-negotiation - * advertisement register after link down event in SkPhyIsrGmac(). - * - * Revision 1.85 2003/04/08 16:39:02 rschmidt - * Changed handling for different PhyTypes for source code - * portability to PXE, UNDI. - * Editorial changes. - * - * Revision 1.84 2003/03/31 07:01:43 mkarl - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.83 2003/02/05 15:10:59 rschmidt - * Fixed setting of PLinkSpeedUsed in SkHWLinkUp() when - * auto-negotiation is disabled. - * Editorial changes. - * - * Revision 1.82 2003/01/29 13:34:33 rschmidt - * Added some typecasts to avoid compiler warnings. - * - * Revision 1.81 2002/12/05 10:49:51 rschmidt - * Fixed missing Link Down Event for fiber (Bug Id #10768) - * Added reading of cable length when link is up - * Removed testing of unused error bits in PHY ISR - * Editorial changes. - * - * Revision 1.80 2002/11/12 17:15:21 rschmidt - * Replaced SkPnmiGetVar() by ...MacStatistic() in SkMacParity(). - * Editorial changes. - * - * Revision 1.79 2002/10/14 15:14:51 rschmidt - * Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in - * SkMacParity() depending on GIChipRev (HW-Bug #8). - * Added error messages for GPHY Auto-Negotiation Error and - * FIFO Overflow/Underrun in SkPhyIsrGmac(). - * Editorial changes. - * - * Revision 1.78 2002/10/10 15:54:29 mkarl - * changes for PLinkSpeedUsed - * - * Revision 1.77 2002/09/12 08:58:51 rwahl - * Retrieve counters needed for XMAC errata workarounds directly because - * PNMI returns corrected counter values (e.g. #10620). - * - * Revision 1.76 2002/08/16 15:21:54 rschmidt - * Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis. - * Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros. - * Editorial changes. - * - * Revision 1.75 2002/08/12 13:50:47 rschmidt - * Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in - * SkMacParity() by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE (HW-Bug #8). - * Added clearing of IS_IRQ_TIST_OV and IS_IRQ_SENSOR in SkGeHwErr(). - * Corrected handling of Link Up and Auto-Negotiation Over for GPHY. - * in SkGePortCheckUpGmac(). - * Editorial changes. - * - * Revision 1.74 2002/08/08 16:17:04 rschmidt - * Added PhyType check for SK_HWEV_SET_ROLE event (copper only) - * Changed Link Up check reading PHY Specific Status (YUKON) - * Editorial changes - * - * Revision 1.73 2002/07/15 18:36:53 rwahl - * Editorial changes. - * - * Revision 1.72 2002/07/15 15:46:26 rschmidt - * Added new event: SK_HWEV_SET_SPEED - * Editorial changes - * - * Revision 1.71 2002/06/10 09:34:19 rschmidt - * Editorial changes - * - * Revision 1.70 2002/06/05 08:29:18 rschmidt - * SkXmRxTxEnable() replaced by SkMacRxTxEnable(). - * Editorial changes. - * - * Revision 1.69 2002/04/25 13:03:49 rschmidt - * Changes for handling YUKON. - * Use of #ifdef OTHER_PHY to eliminate code for unused Phy types. - * Replaced all XMAC-access macros by functions: SkMacRxTxDisable(), - * SkMacIrqDisable(). - * Added handling for GMAC FIFO in SkMacParity(). - * Replaced all SkXm...() functions with SkMac...() to handle also - * YUKON's GMAC. - * Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced - * by functions SkXmPhyRead(), SkXmPhyWrite(). - * Disabling all PHY interrupts moved to SkMacIrqDisable(). - * Added handling for GPHY IRQ in SkGeSirqIsr(). - * Removed status parameter from MAC IRQ handler SkMacIrq(). - * Added SkGePortCheckUpGmac(), SkPhyIsrGmac() for GMAC. - * Editorial changes - * - * Revision 1.68 2002/02/26 15:24:53 rwahl - * Fix: no link with manual configuration (#10673). The previous fix for - * #10639 was removed. So for RLMT mode = CLS the RLMT may switch to - * misconfigured port. It should not occur for the other RLMT modes. - * - * Revision 1.67 2001/11/20 09:19:58 rwahl - * Reworked bugfix #10639 (no dependency to RLMT mode). - * - * Revision 1.66 2001/10/26 07:52:53 afischer - * Port switching bug in `check local link` mode - * - * Revision 1.65 2001/02/23 13:41:51 gklug - * fix: PHYS2INST should be used correctly for Dual Net operation - * chg: do no longer work with older PNMI - * - * Revision 1.64 2001/02/15 11:27:04 rassmann - * Working with RLMT v1 if SK_MAX_NETS undefined. - * - * Revision 1.63 2001/02/06 10:44:23 mkunz - * - NetIndex added to interface functions of pnmi V4 with dual net support - * - * Revision 1.62 2001/01/31 15:31:41 gklug - * fix: problem with autosensing an SR8800 switch - * - * Revision 1.61 2000/11/09 11:30:09 rassmann - * WA: Waiting after releasing reset until BCom chip is accessible. - * - * Revision 1.60 2000/10/18 12:37:48 cgoos - * Reinserted the comment for version 1.56. - * - * Revision 1.59 2000/10/18 12:22:20 cgoos - * Added workaround for half duplex hangup. - * - * Revision 1.58 2000/09/28 13:06:04 gklug - * fix: BCom may NOT be touched if XMAC is in RESET state - * - * Revision 1.57 2000/09/08 12:38:39 cgoos - * Added forgotten variable declaration. - * - * Revision 1.56 2000/09/08 08:12:13 cgoos - * Changed handling of parity errors in SkGeHwErr (correct reset of error). - * - * Revision 1.55 2000/06/19 08:36:25 cgoos - * Changed comment. - * - * Revision 1.54 2000/05/22 08:45:57 malthoff - * Fix: #10523 is valid for all BCom PHYs. - * - * Revision 1.53 2000/05/19 10:20:30 cgoos - * Removed Solaris debug output code. - * - * Revision 1.52 2000/05/19 10:19:37 cgoos - * Added PHY state check in HWLinkDown. - * Move PHY interrupt code to IS_EXT_REG case in SkGeSirqIsr. - * - * Revision 1.51 2000/05/18 05:56:20 cgoos - * Fixed typo. - * - * Revision 1.50 2000/05/17 12:49:49 malthoff - * Fixes BCom link bugs (#10523). - * - * Revision 1.49 1999/12/17 11:02:50 gklug - * fix: read PHY_STAT of Broadcom chip more often to assure good status - * - * Revision 1.48 1999/12/06 10:01:17 cgoos - * Added SET function for Role. - * - * Revision 1.47 1999/11/22 13:34:24 cgoos - * Changed license header to GPL. - * - * Revision 1.46 1999/09/16 10:30:07 cgoos - * Removed debugging output statement from Linux. - * - * Revision 1.45 1999/09/16 07:32:55 cgoos - * Fixed dual-port copperfield bug (PHY_READ from resetted port). - * Removed some unused variables. - * - * Revision 1.44 1999/08/03 15:25:04 cgoos - * Removed workaround for disabled interrupts in half duplex mode. - * - * Revision 1.43 1999/08/03 14:27:58 cgoos - * Removed SENSE mode code from SkGePortCheckUpBcom. - * - * Revision 1.42 1999/07/26 09:16:54 cgoos - * Added some typecasts to avoid compiler warnings. - * - * Revision 1.41 1999/05/19 07:28:59 cgoos - * Changes for 1000Base-T. - * - * Revision 1.40 1999/04/08 13:59:39 gklug - * fix: problem with 3Com switches endless RESTARTs - * - * Revision 1.39 1999/03/08 10:10:52 gklug - * fix: AutoSensing did switch to next mode even if LiPa indicated offline - * - * Revision 1.38 1999/03/08 09:49:03 gklug - * fix: Bug using pAC instead of IoC, causing AIX problems - * fix: change compare for Linux compiler bug workaround - * - * Revision 1.37 1999/01/28 14:51:33 gklug - * fix: monitor for autosensing and extra RESETS the RX on wire counters - * - * Revision 1.36 1999/01/22 09:19:55 gklug - * fix: Init DupMode and InitPauseMd are now called in RxTxEnable - * - * Revision 1.35 1998/12/11 15:22:59 gklug - * chg: autosensing: check for receive if manual mode was guessed - * chg: simplified workaround for XMAC errata - * chg: wait additional 100 ms before link goes up. - * chg: autoneg timeout to 600 ms - * chg: restart autoneg even if configured to autonegotiation - * - * Revision 1.34 1998/12/10 10:33:14 gklug - * add: more debug messages - * fix: do a new InitPhy if link went down (AutoSensing problem) - * chg: Check for zero shorts if link is NOT up - * chg: reset Port if link goes down - * chg: wait additional 100 ms when link comes up to check shorts - * fix: dummy read extended autoneg status to prevent link going down immediately - * - * Revision 1.33 1998/12/07 12:18:29 gklug - * add: refinement of autosense mode: take into account the autoneg cap of LiPa - * - * Revision 1.32 1998/12/07 07:11:21 gklug - * fix: compiler warning - * - * Revision 1.31 1998/12/02 09:29:05 gklug - * fix: WA XMAC Errata: FCSCt check was not correct. - * fix: WA XMAC Errata: Prec Counter were NOT updated in case of short checks. - * fix: Clear Stat : now clears the Prev counters of all known Ports - * - * Revision 1.30 1998/12/01 10:54:15 gklug - * dd: workaround for XMAC errata changed. Check RX count and CRC err Count, too. - * - * Revision 1.29 1998/12/01 10:01:53 gklug - * fix: if MAC IRQ occurs during port down, this will be handled correctly - * - * Revision 1.28 1998/11/26 16:22:11 gklug - * fix: bug in autosense if manual modes are used - * - * Revision 1.27 1998/11/26 15:50:06 gklug - * fix: PNMI needs to set PLinkModeConf - * - * Revision 1.26 1998/11/26 14:51:58 gklug - * add: AutoSensing functionalty - * - * Revision 1.25 1998/11/26 07:34:37 gklug - * fix: Init PrevShorts when restarting port due to Link connection - * - * Revision 1.24 1998/11/25 10:57:32 gklug - * fix: remove unreferenced local vars - * - * Revision 1.23 1998/11/25 08:26:40 gklug - * fix: don't do a RESET on a starting or stopping port - * - * Revision 1.22 1998/11/24 13:29:44 gklug - * add: Workaround for MAC parity errata - * - * Revision 1.21 1998/11/18 15:31:06 gklug - * fix: lint bugs - * - * Revision 1.20 1998/11/18 12:58:54 gklug - * fix: use PNMI query instead of hardware access - * - * Revision 1.19 1998/11/18 12:54:55 gklug - * chg: add new workaround for XMAC Errata - * add: short event counter monitoring on active link too - * - * Revision 1.18 1998/11/13 14:27:41 malthoff - * Bug Fix: Packet Arbiter Timeout was not cleared correctly - * for timeout on TX1 and TX2. - * - * Revision 1.17 1998/11/04 07:01:59 cgoos - * Moved HW link poll sequence. - * Added call to SkXmRxTxEnable. - * - * Revision 1.16 1998/11/03 13:46:03 gklug - * add: functionality of SET_LMODE and SET_FLOW_MODE - * fix: send RLMT LinkDown event when Port stop is given with LinkUp - * - * Revision 1.15 1998/11/03 12:56:47 gklug - * fix: Needs more events - * - * Revision 1.14 1998/10/30 07:36:35 gklug - * rmv: unnecessary code - * - * Revision 1.13 1998/10/29 15:21:57 gklug - * add: Poll link feature for activating HW link - * fix: Deactivate HWLink when Port STOP is given - * - * Revision 1.12 1998/10/28 07:38:57 cgoos - * Checking link status at begin of SkHWLinkUp. - * - * Revision 1.11 1998/10/22 09:46:50 gklug - * fix SysKonnectFileId typo - * - * Revision 1.10 1998/10/14 13:57:47 gklug - * add: Port start/stop event - * - * Revision 1.9 1998/10/14 05:48:29 cgoos - * Added definition for Para. - * - * Revision 1.8 1998/10/14 05:40:09 gklug - * add: Hardware Linkup signal used - * - * Revision 1.7 1998/10/09 06:50:20 malthoff - * Remove ID_sccs by SysKonnectFileId. - * - * Revision 1.6 1998/10/08 09:11:49 gklug - * add: clear IRQ commands - * - * Revision 1.5 1998/10/02 14:27:35 cgoos - * Fixed some typos and wrong event names. - * - * Revision 1.4 1998/10/02 06:24:17 gklug - * add: HW error function - * fix: OUT macros - * - * Revision 1.3 1998/10/01 07:03:00 gklug - * add: ISR for the usual interrupt source register - * - * Revision 1.2 1998/09/03 13:50:33 gklug - * add: function prototypes - * - * Revision 1.1 1998/08/27 11:50:21 gklug - * initial revision - * - * - * - ******************************************************************************/ - /* * Special Interrupt handler * diff -urN linux-2.4.25/drivers/net/sk98lin/ski2c.c linux-2.4.26/drivers/net/sk98lin/ski2c.c --- linux-2.4.25/drivers/net/sk98lin/ski2c.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/ski2c.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: ski2c.c * Project: Gigabit Ethernet Adapters, TWSI-Module - * Version: $Revision: 1.59 $ - * Date: $Date: 2003/10/20 09:07:25 $ * Purpose: Functions to access Voltage and Temperature Sensor * ******************************************************************************/ @@ -22,219 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: ski2c.c,v $ - * Revision 1.59 2003/10/20 09:07:25 rschmidt - * Added cast SK_U32 in SkI2cWrite() to avoid compiler warning. - * Editorial changes. - * - * Revision 1.58 2003/09/23 09:22:53 malthoff - * Parameter I2cDevSize added in SkI2cRead and SkI2cWrite to - * support larger devices on the TWSI bus. - * - * Revision 1.57 2003/01/28 09:17:38 rschmidt - * Fixed handling for sensors on YUKON Fiber. - * Editorial changes. - * - * Revision 1.56 2002/12/19 14:20:41 rschmidt - * Added debugging code in SkI2cWait(). - * Replaced all I2C-write operations with function SkI2cWrite(). - * Fixed compiler warning because of uninitialized 'Time' in SkI2cEvent(). - * Editorial changes. - * - * Revision 1.55 2002/10/15 07:23:55 rschmidt - * Added setting of the GIYukon32Bit bool variable to distinguish - * 32-bit adapters. - * Editorial changes (TWSI). - * - * Revision 1.54 2002/08/13 09:05:06 rschmidt - * Added new thresholds if VAUX is not available (GIVauxAvail). - * Merged defines for PHY PLL 3V3 voltage (A and B). - * Editorial changes. - * - * Revision 1.53 2002/08/08 11:04:53 rwahl - * Added missing comment for revision 1.51 - * - * Revision 1.52 2002/08/08 10:09:02 jschmalz - * Sensor init state caused wrong error log entry - * - * Revision 1.51 2002/08/06 09:43:03 jschmalz - * Extensions and changes for Yukon - * - * Revision 1.50 2002/08/02 12:09:22 rschmidt - * Added support for YUKON sensors. - * Editorial changes. - * - * Revision 1.49 2002/07/30 11:07:52 rschmidt - * Replaced MaxSens init by update for Copper in SkI2cInit1(), - * because it was already initialized in SkI2cInit0(). - * Editorial changes. - * - * Revision 1.48 2001/08/16 12:44:33 afischer - * LM80 sensor init values corrected - * - * Revision 1.47 2001/04/05 11:38:09 rassmann - * Set SenState to idle in SkI2cWaitIrq(). - * Changed error message in SkI2cWaitIrq(). - * - * Revision 1.46 2001/04/02 14:03:35 rassmann - * Changed pAC to IoC in SK_IN32(). - * - * Revision 1.45 2001/03/21 12:12:49 rassmann - * Resetting I2C_READY interrupt in SkI2cInit1(). - * - * Revision 1.44 2000/08/07 15:49:03 gklug - * Fix: SK_INFAST only in NetWare driver. - * - * Revision 1.43 2000/08/03 14:28:17 rassmann - * Added function to wait for I2C being ready before resetting the board. - * Replaced one duplicate "out of range" message with correct one. - * - * Revision 1.42 1999/11/22 13:35:12 cgoos - * Changed license header to GPL. - * - * Revision 1.41 1999/09/14 14:11:30 malthoff - * The 1000BT Dual Link adapter has got only one Fan. - * The second Fan has been removed. - * - * Revision 1.40 1999/05/27 13:37:27 malthoff - * Set divisor of 1 for fan count calculation. - * - * Revision 1.39 1999/05/20 14:54:43 malthoff - * I2c.DummyReads is not used in Diagnostics. - * - * Revision 1.38 1999/05/20 09:20:56 cgoos - * Changes for 1000Base-T (up to 9 sensors and fans). - * - * Revision 1.37 1999/03/25 15:11:36 gklug - * fix: reset error flag if sensor reads correct value - * - * Revision 1.36 1999/01/07 14:11:16 gklug - * fix: break added - * - * Revision 1.35 1999/01/05 15:31:49 gklug - * fix: CLEAR STAT command is now added correctly - * - * Revision 1.34 1998/12/01 13:45:16 gklug - * fix: introduced Init level, because we don't need reinits - * - * Revision 1.33 1998/11/09 14:54:25 malthoff - * Modify I2C Transfer Timeout handling for Diagnostics. - * - * Revision 1.32 1998/11/03 06:54:35 gklug - * fix: Need dummy reads at the beginning to init sensors - * - * Revision 1.31 1998/11/03 06:42:42 gklug - * fix: select correctVIO range only if between warning levels - * - * Revision 1.30 1998/11/02 07:36:53 gklug - * fix: Error should not include WARNING message - * - * Revision 1.29 1998/10/30 15:07:43 malthoff - * Disable 'I2C does not compelete' error log for diagnostics. - * - * Revision 1.28 1998/10/22 09:48:11 gklug - * fix: SysKonnectFileId typo - * - * Revision 1.27 1998/10/20 09:59:46 gklug - * add: parameter to SkOsGetTime - * - * Revision 1.26 1998/10/09 06:10:59 malthoff - * Remove ID_sccs by SysKonnectFileId. - * - * Revision 1.25 1998/09/08 12:40:26 gklug - * fix: syntax error in if clause - * - * Revision 1.24 1998/09/08 12:19:42 gklug - * chg: INIT Level checking - * - * Revision 1.23 1998/09/08 07:37:20 gklug - * fix: log error if PCI_IO voltage sensor could not be initialized - * - * Revision 1.22 1998/09/04 08:30:03 malthoff - * Bugfixes during SK_DIAG testing: - * - correct NS2BCLK() macro - * - correct SkI2cSndDev() - * - correct SkI2cWait() loop waiting for an event - * - * Revision 1.21 1998/08/27 14:46:01 gklug - * chg: if-then-else replaced by switch - * - * Revision 1.20 1998/08/27 14:40:07 gklug - * test: integral types - * - * Revision 1.19 1998/08/25 07:51:54 gklug - * fix: typos for compiling - * - * Revision 1.18 1998/08/25 06:12:24 gklug - * add: count errors and warnings - * fix: check not the sensor state but the ErrFlag! - * - * Revision 1.17 1998/08/25 05:56:48 gklug - * add: CheckSensor function - * - * Revision 1.16 1998/08/20 11:41:10 gklug - * chg: omit STRCPY macro by using char * as Sensor Description - * - * Revision 1.15 1998/08/20 11:37:35 gklug - * chg: change Ioc to IoC - * - * Revision 1.14 1998/08/20 11:32:52 gklug - * fix: Para compile error - * - * Revision 1.13 1998/08/20 11:27:41 gklug - * fix: Compile bugs with new awrning constants - * - * Revision 1.12 1998/08/20 08:53:05 gklug - * fix: compiler errors - * add: Threshold values - * - * Revision 1.11 1998/08/19 12:39:22 malthoff - * Compiler Fix: Some names have changed. - * - * Revision 1.10 1998/08/19 12:20:56 gklug - * fix: remove struct from C files (see CCC) - * - * Revision 1.9 1998/08/19 06:28:46 malthoff - * SkOsGetTime returns SK_U64 now. - * - * Revision 1.8 1998/08/17 13:53:33 gklug - * fix: Parameter of event function and its result - * - * Revision 1.7 1998/08/17 07:02:15 malthoff - * Modify the functions for accessing the I2C SW Registers. - * Modify SkI2cWait(). - * Put Lm80RcvReg into sklm80.c - * Remove Compiler Errors. - * - * Revision 1.6 1998/08/14 07:13:20 malthoff - * remove pAc with pAC - * remove smc with pAC - * change names to new convention - * - * Revision 1.5 1998/08/14 06:24:49 gklug - * add: init level 1 and 2 - * - * Revision 1.4 1998/08/12 14:31:12 gklug - * add: error log for unknown event - * - * Revision 1.3 1998/08/12 13:37:04 gklug - * add: Init 0 function - * - * Revision 1.2 1998/08/11 07:27:15 gklug - * add: functions of the interface - * adapt rest of source to C coding Conventions - * rmv: unnecessary code taken from Mona Lisa - * - * Revision 1.1 1998/06/19 14:28:43 malthoff - * Created. Sources taken from ML Projekt. - * Sources have to be reworked for GE. - * - ******************************************************************************/ - /* * I2C Protocol */ diff -urN linux-2.4.25/drivers/net/sk98lin/sklm80.c linux-2.4.26/drivers/net/sk98lin/sklm80.c --- linux-2.4.25/drivers/net/sk98lin/sklm80.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/sklm80.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: sklm80.c * Project: Gigabit Ethernet Adapters, TWSI-Module - * Version: $Revision: 1.22 $ - * Date: $Date: 2003/10/20 09:08:21 $ * Purpose: Functions to access Voltage and Temperature Sensor (LM80) * ******************************************************************************/ @@ -22,86 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: sklm80.c,v $ - * Revision 1.22 2003/10/20 09:08:21 rschmidt - * Editorial changes. - * - * Revision 1.21 2003/09/23 09:29:04 malthoff - * Parameter Dev_Size added to macro SK_I2C_CTL. - * - * Revision 1.20 2002/08/13 09:16:27 rschmidt - * Changed return value for SkLm80ReadSensor() back to 'int' - * Editorial changes. - * - * Revision 1.19 2002/08/06 09:43:31 jschmalz - * Extensions and changes for Yukon. - * - * Revision 1.18 2002/08/02 12:26:57 rschmidt - * Editorial changes. - * - * Revision 1.17 1999/11/22 13:35:51 cgoos - * Changed license header to GPL. - * - * Revision 1.16 1999/05/27 14:05:47 malthoff - * Fans: Set SenVal to 0 if the fan value is 0 or 0xff. Both values - * are outside the limits (0: div zero error, 0xff: value not in - * range, assume 0). - * - * Revision 1.15 1999/05/27 13:38:51 malthoff - * Pervent from Division by zero errors. - * - * Revision 1.14 1999/05/20 09:20:01 cgoos - * Changes for 1000Base-T (Fan sensors). - * - * Revision 1.13 1998/10/22 09:48:14 gklug - * fix: SysKonnectFileId typo - * - * Revision 1.12 1998/10/09 06:12:06 malthoff - * Remove ID_sccs by SysKonnectFileId. - * - * Revision 1.11 1998/09/04 08:33:48 malthoff - * bug fix: SenState = SK_SEN_IDLE when - * leaving SK_SEN_VALEXT state - * - * Revision 1.10 1998/08/20 12:02:10 gklug - * fix: compiler warnings type mismatch - * - * Revision 1.9 1998/08/20 11:37:38 gklug - * chg: change Ioc to IoC - * - * Revision 1.8 1998/08/19 12:20:58 gklug - * fix: remove struct from C files (see CCC) - * - * Revision 1.7 1998/08/17 07:04:57 malthoff - * Take SkLm80RcvReg() function from ski2c.c. - * Add IoC parameter to BREAK_OR_WAIT() macro. - * - * Revision 1.6 1998/08/14 07:11:28 malthoff - * remove pAc with pAC. - * - * Revision 1.5 1998/08/14 06:46:55 gklug - * fix: temperature can get negative - * - * Revision 1.4 1998/08/13 08:27:04 gklug - * add: temperature reading now o.k. - * fix: pSen declaration, SK_ERR_LOG call, ADDR macro - * - * Revision 1.3 1998/08/13 07:28:21 gklug - * fix: pSen was wrong initialized - * add: correct conversion for voltage readings - * - * Revision 1.2 1998/08/11 07:52:14 gklug - * add: Lm80 read sensor function - * - * Revision 1.1 1998/07/17 09:57:12 gklug - * initial version - * - ******************************************************************************/ - /* LM80 functions */ diff -urN linux-2.4.25/drivers/net/sk98lin/skproc.c linux-2.4.26/drivers/net/sk98lin/skproc.c --- linux-2.4.25/drivers/net/sk98lin/skproc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skproc.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skproc.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 2003/12/11 16:03:57 $ * Purpose: Funktions to display statictic data * ******************************************************************************/ @@ -24,98 +22,6 @@ * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skproc.c,v $ - * Revision 1.11 2003/12/11 16:03:57 mlindner - * Fix: Create backup from pnmi data structure - * - * Revision 1.10 2003/11/19 16:25:36 mlindner - * Fix: Print output as 64-bit digit - * - * Revision 1.9 2003/11/17 13:29:05 mlindner - * Fix: Editorial changes - * - * Revision 1.8 2003/11/13 14:18:48 rroesler - * Fix: added latest changes regarding the use of the proc system - * - * Revision 1.7 2003/11/10 09:35:07 rroesler - * Fix: diag backup restore of PNMI structure - * - * Revision 1.6 2003/11/07 17:31:39 rroesler - * Add: security counter for the proc file system - * - * Revision 1.5 2003/10/07 08:17:08 mlindner - * Fix: Copyright changes - * - * Revision 1.4 2003/09/01 15:29:24 mlindner - * Fix: Editorial changes - * - * Revision 1.3 2003/08/29 12:30:58 mlindner - * Add: Version entry in the proc file system - * - * Revision 1.2 2003/08/12 16:45:29 mlindner - * Add: Removed SkNumber and SkDoDiv - * Add: Counter output as (unsigned long long) - * - * Revision 1.1 2003/07/18 13:39:57 rroesler - * Fix: Re-enter after CVS crash - * - * Revision 1.8 2003/06/27 14:41:42 rroesler - * Corrected compiler-warning kernel 2.2 - * - * Revision 1.7 2003/06/27 12:09:51 rroesler - * corrected minor edits - * - * Revision 1.6 2003/05/26 12:58:53 mlindner - * Add: Support for Kernel 2.5/2.6 - * - * Revision 1.5 2003/03/19 14:40:47 mlindner - * Fix: Editorial changes - * - * Revision 1.4 2003/02/25 14:16:37 mlindner - * Fix: Copyright statement - * - * Revision 1.3 2002/10/02 12:59:51 mlindner - * Add: Support for Yukon - * Add: Speed check and setup - * Add: Merge source for kernel 2.2.x and 2.4.x - * Add: Read sensor names directly from VPD - * Fix: Volt values - * - * Revision 1.2.2.7 2002/01/14 12:45:15 mlindner - * Fix: Editorial changes - * - * Revision 1.2.2.6 2001/12/06 15:26:07 mlindner - * Fix: Return value of proc_read - * - * Revision 1.2.2.5 2001/12/06 09:57:39 mlindner - * New ProcFs entries - * - * Revision 1.2.2.4 2001/09/05 12:16:02 mlindner - * Add: New ProcFs entries - * Fix: Counter Errors (Jumbo == to long errors) - * Fix: Kernel error compilation - * Fix: too short counters - * - * Revision 1.2.2.3 2001/06/25 07:26:26 mlindner - * Add: More error messages - * - * Revision 1.2.2.2 2001/03/15 12:50:13 mlindner - * fix: ProcFS owner protection - * - * Revision 1.2.2.1 2001/03/12 16:43:48 mlindner - * chg: 2.4 requirements for procfs - * - * Revision 1.1 2001/01/22 14:15:31 mlindner - * added ProcFs functionality - * Dual Net functionality integrated - * Rlmt networks added - * - * - ******************************************************************************/ #include diff -urN linux-2.4.25/drivers/net/sk98lin/skqueue.c linux-2.4.26/drivers/net/sk98lin/skqueue.c --- linux-2.4.25/drivers/net/sk98lin/skqueue.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skqueue.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skqueue.c * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.20 $ - * Date: $Date: 2003/09/16 13:44:00 $ * Purpose: Management of an event queue. * ******************************************************************************/ @@ -22,77 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skqueue.c,v $ - * Revision 1.20 2003/09/16 13:44:00 rschmidt - * Added (C) Marvell to SysKonnectFileId - * Editorial changes - * - * Revision 1.19 2003/05/13 18:00:07 mkarl - * Removed calls to RLMT, TWSI, and PNMI for SLIM driver (SK_SLIM). - * Editorial changes. - * - * Revision 1.18 2002/05/07 14:11:11 rwahl - * Fixed Watcom Precompiler error. - * - * Revision 1.17 2002/03/25 10:06:41 mkunz - * SkIgnoreEvent deleted - * - * Revision 1.16 2002/03/15 10:51:59 mkunz - * Added event classes for link aggregation - * - * Revision 1.15 1999/11/22 13:36:29 cgoos - * Changed license header to GPL. - * - * Revision 1.14 1998/10/15 15:11:35 gklug - * fix: ID_sccs to SysKonnectFileId - * - * Revision 1.13 1998/09/08 08:47:52 gklug - * add: init level handling - * - * Revision 1.12 1998/09/08 07:43:20 gklug - * fix: Sirq Event function name - * - * Revision 1.11 1998/09/08 05:54:34 gklug - * chg: define SK_CSUM is replaced by SK_USE_CSUM - * - * Revision 1.10 1998/09/03 14:14:49 gklug - * add: CSUM and HWAC Eventclass and function. - * - * Revision 1.9 1998/08/19 09:50:50 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs - * - * Revision 1.8 1998/08/17 13:43:11 gklug - * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR - * - * Revision 1.7 1998/08/14 07:09:11 gklug - * fix: chg pAc -> pAC - * - * Revision 1.6 1998/08/11 12:13:14 gklug - * add: return code feature of Event service routines - * add: correct Error log calls - * - * Revision 1.5 1998/08/07 12:53:45 gklug - * fix: first compiled version - * - * Revision 1.4 1998/08/07 09:20:48 gklug - * adapt functions to C coding conventions. - * - * Revision 1.3 1998/08/05 11:29:32 gklug - * rmv: Timer event entry. Timer will queue event directly - * - * Revision 1.2 1998/07/31 11:22:40 gklug - * Initial version - * - * Revision 1.1 1998/07/30 15:14:01 gklug - * Initial version. Adapted from SMT - * - ******************************************************************************/ - - /* * Event queue and dispatcher */ diff -urN linux-2.4.25/drivers/net/sk98lin/skrlmt.c linux-2.4.26/drivers/net/sk98lin/skrlmt.c --- linux-2.4.25/drivers/net/sk98lin/skrlmt.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skrlmt.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skrlmt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.69 $ - * Date: $Date: 2003/04/15 09:39:22 $ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. * ******************************************************************************/ @@ -24,254 +22,6 @@ /****************************************************************************** * - * History: - * - * $Log: skrlmt.c,v $ - * Revision 1.69 2003/04/15 09:39:22 tschilli - * Copyright messages changed. - * "#error C++ is not yet supported." removed. - * - * Revision 1.68 2003/01/31 15:26:56 rschmidt - * Added init for local variables in RlmtInit(). - * - * Revision 1.67 2003/01/31 14:12:41 mkunz - * single port adapter runs now with two identical MAC addresses - * - * Revision 1.66 2002/09/23 15:14:19 rwahl - * - Reset broadcast timestamp on link down. - * - Editorial corrections. - * - * Revision 1.65 2002/07/22 14:29:48 rwahl - * - Removed BRK statement from debug check. - * - * Revision 1.64 2001/11/28 19:36:14 rwahl - * - RLMT Packets sent to an invalid MAC address in CLP/CLPSS mode - * (#10650). - * - Reworked fix for port switching in CLS mode (#10639) - * (no dependency to RLMT module). - * - Enabled dbg output for entry/exit of event functions. - * - Editorial changes. - * - * Revision 1.63 2001/10/26 07:53:18 afischer - * Port switching bug in `check local link` mode - * - * Revision 1.62 2001/07/03 12:16:30 mkunz - * New Flag ChgBcPrio (Change priority of last broadcast received) - * - * Revision 1.61 2001/03/14 12:52:08 rassmann - * Fixed reporting of active port up/down to PNMI. - * - * Revision 1.60 2001/02/21 16:02:25 gklug - * fix: when RLMT starts set Active Port for PNMI - * - * Revision 1.59 2001/02/16 14:38:19 rassmann - * Initializing some pointers earlier in the init phase. - * Rx Mbufs are freed if the net which they belong to is stopped. - * - * Revision 1.58 2001/02/14 14:06:31 rassmann - * Editorial changes. - * - * Revision 1.57 2001/02/05 14:25:26 rassmann - * Prepared RLMT for transparent operation. - * - * Revision 1.56 2001/01/30 10:29:09 rassmann - * Not checking switching befor RlmtStart. - * Editorial changes. - * - * Revision 1.55 2001/01/22 13:41:38 rassmann - * Supporting two nets on dual-port adapters. - * - * Revision 1.54 2000/11/30 13:25:07 rassmann - * Setting SK_TICK_INCR to 1 by default. - * - * Revision 1.53 2000/11/30 10:48:07 cgoos - * Changed definition of SK_RLMT_BC_DELTA. - * - * Revision 1.52 2000/11/27 12:50:03 rassmann - * Checking ports after receiving broadcasts. - * - * Revision 1.51 2000/11/17 08:58:00 rassmann - * Moved CheckSwitch from SK_RLMT_PACKET_RECEIVED to SK_RLMT_TIM event. - * - * Revision 1.50 2000/11/09 12:24:34 rassmann - * Indicating that segmentation check is not running anymore after - * SkRlmtCheckSeg(). - * Restarting segmentation timer after segmentation log. - * Editorial changes. - * - * Revision 1.49 1999/11/22 13:38:02 cgoos - * Changed license header to GPL. - * Added initialization to some variables to avoid compiler warnings. - * - * Revision 1.48 1999/10/04 14:01:17 rassmann - * Corrected reaction to reception of BPDU frames (#10441). - * - * Revision 1.47 1999/07/20 12:53:36 rassmann - * Fixed documentation errors for lookahead macros. - * - * Revision 1.46 1999/05/28 13:29:16 rassmann - * Replaced C++-style comment. - * - * Revision 1.45 1999/05/28 13:28:08 rassmann - * Corrected syntax error (xxx). - * - * Revision 1.44 1999/05/28 11:15:54 rassmann - * Changed behaviour to reflect Design Spec v1.2. - * Controlling Link LED(s). - * Introduced RLMT Packet Version field in RLMT Packet. - * Newstyle lookahead macros (checking meta-information before looking at - * the packet). - * - * Revision 1.43 1999/01/28 13:12:43 rassmann - * Corrected Lookahead (bug introduced in previous Rev.). - * - * Revision 1.42 1999/01/28 12:50:41 rassmann - * Not using broadcast time stamps in CheckLinkState mode. - * - * Revision 1.41 1999/01/27 14:13:02 rassmann - * Monitoring broadcast traffic. - * Switching more reliably and not too early if switch is - * configured for spanning tree. - * - * Revision 1.40 1999/01/22 13:17:30 rassmann - * Informing PNMI of NET_UP. - * Clearing RLMT multicast addresses before setting them for the first time. - * Reporting segmentation earlier, setting a "quiet time" - * after a report. - * - * Revision 1.39 1998/12/10 15:29:53 rassmann - * Corrected SuspectStatus in SkRlmtBuildCheckChain(). - * Corrected CHECK_SEG mode. - * - * Revision 1.38 1998/12/08 13:11:23 rassmann - * Stopping SegTimer at RlmtStop. - * - * Revision 1.37 1998/12/07 16:51:42 rassmann - * Corrected comments. - * - * Revision 1.36 1998/12/04 10:58:56 rassmann - * Setting next pointer to NULL when receiving. - * - * Revision 1.35 1998/12/03 16:12:42 rassmann - * Ignoring/correcting illegal PrefPort values. - * - * Revision 1.34 1998/12/01 11:45:35 rassmann - * Code cleanup. - * - * Revision 1.33 1998/12/01 10:29:32 rassmann - * Starting standby ports before getting the net up. - * Checking if a port is started when the link comes up. - * - * Revision 1.32 1998/11/30 16:19:50 rassmann - * New default for PortNoRx. - * - * Revision 1.31 1998/11/27 19:17:13 rassmann - * Corrected handling of LINK_DOWN coming shortly after LINK_UP. - * - * Revision 1.30 1998/11/24 12:37:31 rassmann - * Implemented segmentation check. - * - * Revision 1.29 1998/11/18 13:04:32 rassmann - * Secured PortUpTimer event. - * Waiting longer before starting standby port(s). - * - * Revision 1.28 1998/11/17 13:43:04 rassmann - * Handling (logical) tx failure. - * Sending packet on logical address after PORT_SWITCH. - * - * Revision 1.27 1998/11/13 17:09:50 rassmann - * Secured some events against being called in wrong state. - * - * Revision 1.26 1998/11/13 16:56:54 rassmann - * Added macro version of SkRlmtLookaheadPacket. - * - * Revision 1.25 1998/11/06 18:06:04 rassmann - * Corrected timing when RLMT checks fail. - * Clearing tx counter earlier in periodical checks. - * - * Revision 1.24 1998/11/05 10:37:27 rassmann - * Checking destination address in Lookahead. - * - * Revision 1.23 1998/11/03 13:53:49 rassmann - * RLMT should switch now (at least in mode 3). - * - * Revision 1.22 1998/10/29 14:34:49 rassmann - * Clearing SK_RLMT struct at startup. - * Initializing PortsUp during SK_RLMT_START. - * - * Revision 1.21 1998/10/28 11:30:17 rassmann - * Default mode is now SK_RLMT_CHECK_LOC_LINK. - * - * Revision 1.20 1998/10/26 16:02:03 rassmann - * Ignoring LINK_DOWN for links that are down. - * - * Revision 1.19 1998/10/22 15:54:01 rassmann - * Corrected EtherLen. - * Starting Link Check when second port comes up. - * - * Revision 1.18 1998/10/22 11:39:50 rassmann - * Corrected signed/unsigned mismatches. - * Corrected receive list handling and address recognition. - * - * Revision 1.17 1998/10/19 17:01:20 rassmann - * More detailed checking of received packets. - * - * Revision 1.16 1998/10/15 15:16:34 rassmann - * Finished Spanning Tree checking. - * Checked with lint. - * - * Revision 1.15 1998/09/24 19:16:07 rassmann - * Code cleanup. - * Introduced Timer for PORT_DOWN due to no RX. - * - * Revision 1.14 1998/09/18 20:27:14 rassmann - * Added address override. - * - * Revision 1.13 1998/09/16 11:31:48 rassmann - * Including skdrv1st.h again. :( - * - * Revision 1.12 1998/09/16 11:09:50 rassmann - * Syntax corrections. - * - * Revision 1.11 1998/09/15 12:32:03 rassmann - * Syntax correction. - * - * Revision 1.10 1998/09/15 11:28:49 rassmann - * Syntax corrections. - * - * Revision 1.9 1998/09/14 17:07:37 rassmann - * Added code for port checking via LAN. - * Changed Mbuf definition. - * - * Revision 1.8 1998/09/07 11:14:14 rassmann - * Syntax corrections. - * - * Revision 1.7 1998/09/07 09:06:07 rassmann - * Syntax corrections. - * - * Revision 1.6 1998/09/04 19:41:33 rassmann - * Syntax corrections. - * Started entering code for checking local links. - * - * Revision 1.5 1998/09/04 12:14:27 rassmann - * Interface cleanup. - * - * Revision 1.4 1998/09/02 16:55:28 rassmann - * Updated to reflect new DRV/HWAC/RLMT interface. - * - * Revision 1.3 1998/08/27 14:29:03 rassmann - * Code cleanup. - * - * Revision 1.2 1998/08/27 14:26:24 rassmann - * Updated interface. - * - * Revision 1.1 1998/08/21 08:26:49 rassmann - * First public version. - * - ******************************************************************************/ - -/****************************************************************************** - * * Description: * * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters. diff -urN linux-2.4.25/drivers/net/sk98lin/sktimer.c linux-2.4.26/drivers/net/sk98lin/sktimer.c --- linux-2.4.25/drivers/net/sk98lin/sktimer.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/sktimer.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: sktimer.c * Project: Gigabit Ethernet Adapters, Event Scheduler Module - * Version: $Revision: 1.14 $ - * Date: $Date: 2003/09/16 13:46:51 $ * Purpose: High level timer functions. * ******************************************************************************/ @@ -22,60 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: sktimer.c,v $ - * Revision 1.14 2003/09/16 13:46:51 rschmidt - * Added (C) Marvell to SysKonnectFileId - * Editorial changes - * - * Revision 1.13 2003/05/13 18:01:01 mkarl - * Editorial changes. - * - * Revision 1.12 1999/11/22 13:38:51 cgoos - * Changed license header to GPL. - * - * Revision 1.11 1998/12/17 13:24:13 gklug - * fix: restart problem: do NOT destroy timer queue if init 1 is done - * - * Revision 1.10 1998/10/15 15:11:36 gklug - * fix: ID_sccs to SysKonnectFileId - * - * Revision 1.9 1998/09/15 15:15:04 cgoos - * Changed TRUE/FALSE to SK_TRUE/SK_FALSE - * - * Revision 1.8 1998/09/08 08:47:55 gklug - * add: init level handling - * - * Revision 1.7 1998/08/19 09:50:53 gklug - * fix: remove struct keyword from c-code (see CCC) add typedefs - * - * Revision 1.6 1998/08/17 13:43:13 gklug - * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR - * - * Revision 1.5 1998/08/14 07:09:14 gklug - * fix: chg pAc -> pAC - * - * Revision 1.4 1998/08/07 12:53:46 gklug - * fix: first compiled version - * - * Revision 1.3 1998/08/07 09:31:53 gklug - * fix: delta spelling - * - * Revision 1.2 1998/08/07 09:31:02 gklug - * adapt functions to new c coding conventions - * rmv: "fast" handling - * chg: inserting of new timer in queue. - * chg: event queue generation when timer runs out - * - * Revision 1.1 1998/08/05 11:27:55 gklug - * first version: adapted from SMT - * - ******************************************************************************/ - - /* * Event queue and dispatcher */ diff -urN linux-2.4.25/drivers/net/sk98lin/skvpd.c linux-2.4.26/drivers/net/sk98lin/skvpd.c --- linux-2.4.25/drivers/net/sk98lin/skvpd.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skvpd.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skvpd.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.37 $ - * Date: $Date: 2003/01/13 10:42:45 $ * Purpose: Shared software to read and write VPD data * ******************************************************************************/ @@ -21,145 +19,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skvpd.c,v $ - * Revision 1.37 2003/01/13 10:42:45 rschmidt - * Replaced check for PCI device Id from YUKON with GENESIS - * to set the VPD size in VpdInit() - * Editorial changes - * - * Revision 1.36 2002/11/14 15:16:56 gheinig - * Added const specifier to key and buf parameters for VpdPara, VpdRead - * and VpdWrite for Diag 7 GUI - * - * Revision 1.35 2002/10/21 14:31:59 gheinig - * Took out CVS web garbage at head of file - * - * Revision 1.34 2002/10/21 11:47:24 gheinig - * Reverted to version 1.32 due to unwanted commit - * - * Revision 1.32 2002/10/14 16:04:29 rschmidt - * Added saving of VPD ROM Size from PCI_OUR_REG_2 - * Avoid reading of PCI_OUR_REG_2 in VpdTransferBlock() - * Editorial changes - * - * Revision 1.31 2002/09/10 09:21:32 mkarl - * Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis - * - * Revision 1.30 2002/09/09 14:43:03 mkarl - * changes for diagnostics in order to read VPD data before the adapter - * has been initialized - * editorial changes - * - * Revision 1.29 2002/07/26 13:20:43 mkarl - * added Yukon support - * save size of VPD in pAC->vpd.vpd_size - * - * Revision 1.28 2002/04/02 15:31:47 afischer - * Bug fix in VpdWait() - * - * Revision 1.27 2000/08/10 11:29:06 rassmann - * Editorial changes. - * Preserving 32-bit alignment in structs for the adapter context. - * Removed unused function VpdWriteDword() (#if 0). - * Made VpdReadKeyword() available for SKDIAG only. - * - * Revision 1.26 2000/06/13 08:00:01 mkarl - * additional cast to avoid compile problems in 64 bit environment - * - * Revision 1.25 1999/11/22 13:39:32 cgoos - * Changed license header to GPL. - * - * Revision 1.24 1999/03/11 14:25:49 malthoff - * Replace __STDC__ with SK_KR_PROTO. - * - * Revision 1.23 1999/01/11 15:13:11 gklug - * fix: syntax error - * - * Revision 1.22 1998/10/30 06:41:15 gklug - * rmv: WARNING - * - * Revision 1.21 1998/10/29 07:15:14 gklug - * fix: Write Stream function needs verify. - * - * Revision 1.20 1998/10/28 18:05:08 gklug - * chg: no DEBUG in VpdMayWrite - * - * Revision 1.19 1998/10/28 15:56:11 gklug - * fix: Return len at end of ReadStream - * fix: Write even less than 4 bytes correctly - * - * Revision 1.18 1998/10/28 09:00:47 gklug - * fix: unreferenced local vars - * - * Revision 1.17 1998/10/28 08:25:45 gklug - * fix: WARNING - * - * Revision 1.16 1998/10/28 08:17:30 gklug - * fix: typo - * - * Revision 1.15 1998/10/28 07:50:32 gklug - * fix: typo - * - * Revision 1.14 1998/10/28 07:20:38 gklug - * chg: Interface functions to use IoC as parameter as well - * fix: VpdRead/WriteDWord now returns SK_U32 - * chg: VPD_IN/OUT names conform to SK_IN/OUT - * add: usage of VPD_IN/OUT8 macros - * add: VpdRead/Write Stream functions to r/w a stream of data - * fix: VpdTransferBlock swapped illegal - * add: VpdMayWrite - * - * Revision 1.13 1998/10/22 10:02:37 gklug - * fix: SysKonnectFileId typo - * - * Revision 1.12 1998/10/20 10:01:01 gklug - * fix: parameter to SkOsGetTime - * - * Revision 1.11 1998/10/15 12:51:48 malthoff - * Remove unrequired parameter p in vpd_setup_para(). - * - * Revision 1.10 1998/10/08 14:52:43 malthoff - * Remove CvsId by SysKonnectFileId. - * - * Revision 1.9 1998/09/16 07:33:52 malthoff - * replace memcmp() by SK_MEMCMP and - * memcpy() by SK_MEMCPY() to be - * independent from the 'C' Standard Library. - * - * Revision 1.8 1998/08/19 12:52:35 malthoff - * compiler fix: use SK_VPD_KEY instead of S_VPD. - * - * Revision 1.7 1998/08/19 08:14:01 gklug - * fix: remove struct keyword as much as possible from the C-code (see CCC) - * - * Revision 1.6 1998/08/18 13:03:58 gklug - * SkOsGetTime now returns SK_U64 - * - * Revision 1.5 1998/08/18 08:17:29 malthoff - * Ensure we issue a VPD read in vpd_read_dword(). - * Discard all VPD keywords other than Vx or Yx, where - * x is '0..9' or 'A..Z'. - * - * Revision 1.4 1998/07/03 14:52:19 malthoff - * Add category SK_DBGCAT_FATAL to some debug macros. - * bug fix: correct the keyword name check in vpd_write(). - * - * Revision 1.3 1998/06/26 11:16:53 malthoff - * Correct the modified File Identifier. - * - * Revision 1.2 1998/06/26 11:13:43 malthoff - * Modify the File Identifier. - * - * Revision 1.1 1998/06/19 14:11:08 malthoff - * Created, Tests with AIX were performed successfully - * - * - ******************************************************************************/ - /* Please refer skvpd.txt for infomation how to include this module */ diff -urN linux-2.4.25/drivers/net/sk98lin/skxmac2.c linux-2.4.26/drivers/net/sk98lin/skxmac2.c --- linux-2.4.25/drivers/net/sk98lin/skxmac2.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/sk98lin/skxmac2.c 2004-04-14 06:05:30.000000000 -0700 @@ -2,8 +2,6 @@ * * Name: skxmac2.c * Project: Gigabit Ethernet Adapters, Common Modules - * Version: $Revision: 1.102 $ - * Date: $Date: 2003/10/02 16:53:58 $ * Purpose: Contains functions to initialize the MACs and PHYs * ******************************************************************************/ @@ -22,461 +20,6 @@ * ******************************************************************************/ -/****************************************************************************** - * - * History: - * - * $Log: skxmac2.c,v $ - * Revision 1.102 2003/10/02 16:53:58 rschmidt - * Changed setting of GMAC parameters with new macros. - * Added define SLIM around SkGm...LowPowerMode(). - * Editorial changes. - * - * Revision 1.101 2003/09/16 14:49:07 rschmidt - * Added routines SkGmClearRst(), SkXmClearRst, SkMacClearRst(). - * Added WA code for Yukon-Lite's COMA mode in SkGmHardRst(). - * Replaced PCI-Config R/W through internal access. - * Fixed return from coma mode in SkGmLeaveLowPowerMode(). - * Fixed compiler warnings for different types. - * Editorial changes. - * - * Revision 1.100 2003/09/16 07:09:11 mschmid - * Added functions SkGmEnterLowPowerMode() and - * SkGmLeaveLowPowerMode() - * - * Revision 1.99 2003/07/11 12:19:33 rschmidt - * Reduced init values for Master & Slave downshift counters to - * minimum values. - * Editorial changes. - * - * Revision 1.98 2003/07/04 12:53:56 rschmidt - * Changed setting of downshift feature in SkGmInitPhyMarv(). - * Enabled downshift feature only for para 'Speed' set to 'Auto'. - * Changed init values for Master & Slave downshift counters. - * Editorial changes. - * - * Revision 1.97 2003/05/28 15:53:47 rschmidt - * Removed setting of Yukon PHY's 'force link good' in loopback mode. - * Replaced call pFnMacOverflow() with SkXmOverflowStatus() resp. - * SkGmOverflowStatus(). - * Editorial changes. - * - * Revision 1.96 2003/05/13 17:37:11 mkarl - * Removed calls to PNMI for SLIM driver. - * Added SK_FAR for PXE. - * Separated code pathes not used for SLIM driver. - * Some further separations for YUKON and GENESIS. - * Editorial changes. - * - * Revision 1.95 2003/05/06 13:09:53 rschmidt - * Changed init sequence for auto-negotiation disabled in SkGmInitMac(). - * Added defines around GENESIS resp. YUKON branches to reduce - * code size for PXE. - * Editorial changes. - * - * Revision 1.94 2003/04/10 14:36:40 rschmidt - * Fixed define for debug code in SkGmInitPhyMarv(). - * - * Revision 1.93 2003/04/08 16:58:16 rschmidt - * Changed initialisation of GMAC and GPHY for disabling - * Flow-Control with parameter 'none' (Bug Id #10769). - * Changed init for blinking active LED and normal duplex LED - * depending on value from GILedBlinkCtrl (LED Blink Control). - * Added control for Link100 LED. - * Changed handling for different PhyTypes for source code - * portability to PXE, UNDI. - * Editorial changes. - * - * Revision 1.92 2003/03/31 07:12:33 mkarl - * Restore PHY_MARV_AUNE_ADV after writing to GM_GP_CTRL in order to make - * auto-negotiation of limited flow-control possible. - * Corrected Copyright. - * Editorial changes. - * - * Revision 1.91 2003/02/05 15:09:34 rschmidt - * Removed setting of 'Collision Test'-bit in SkGmInitPhyMarv(). - * Disabled auto-update for speed, duplex and flow-control when - * auto-negotiation is not enabled (Bug Id #10766). - * Editorial changes. - * - * Revision 1.90 2003/01/29 13:35:19 rschmidt - * Increment Rx FIFO Overflow counter only in DEBUG-mode. - * Corrected define for blinking active LED. - * - * Revision 1.89 2003/01/28 16:37:45 rschmidt - * Changed init for blinking active LED - * - * Revision 1.88 2003/01/28 10:09:38 rschmidt - * Added debug outputs in SkGmInitMac(). - * Added customized init of LED registers in SkGmInitPhyMarv(), - * for blinking active LED (#ifdef ACT_LED_BLINK) and - * for normal duplex LED (#ifdef DUP_LED_NORMAL). - * Editorial changes. - * - * Revision 1.87 2002/12/10 14:39:05 rschmidt - * Improved initialization of GPHY in SkGmInitPhyMarv(). - * Editorial changes. - * - * Revision 1.86 2002/12/09 15:01:12 rschmidt - * Added setup of Ext. PHY Specific Ctrl Reg (downshift feature). - * - * Revision 1.85 2002/12/05 14:09:16 rschmidt - * Improved avoiding endless loop in SkGmPhyRead(), SkGmPhyWrite(). - * Added additional advertising for 10Base-T when 100Base-T is selected. - * Added case SK_PHY_MARV_FIBER for YUKON Fiber adapter. - * Editorial changes. - * - * Revision 1.84 2002/11/15 12:50:09 rschmidt - * Changed SkGmCableDiagStatus() when getting results. - * - * Revision 1.83 2002/11/13 10:28:29 rschmidt - * Added some typecasts to avoid compiler warnings. - * - * Revision 1.82 2002/11/13 09:20:46 rschmidt - * Replaced for(..) with do {} while (...) in SkXmUpdateStats(). - * Replaced 2 macros GM_IN16() with 1 GM_IN32() in SkGmMacStatistic(). - * Added SkGmCableDiagStatus() for Virtual Cable Test (VCT). - * Editorial changes. - * - * Revision 1.81 2002/10/28 14:28:08 rschmidt - * Changed MAC address setup for GMAC in SkGmInitMac(). - * Optimized handling of counter overflow IRQ in SkGmOverflowStatus(). - * Editorial changes. - * - * Revision 1.80 2002/10/14 15:29:44 rschmidt - * Corrected disabling of all PHY IRQs. - * Added WA for deviation #16 (address used for pause packets). - * Set Pause Mode in SkMacRxTxEnable() only for Genesis. - * Added IRQ and counter for Receive FIFO Overflow in DEBUG-mode. - * SkXmTimeStamp() replaced by SkMacTimeStamp(). - * Added clearing of GMAC Tx FIFO Underrun IRQ in SkGmIrq(). - * Editorial changes. - * - * Revision 1.79 2002/10/10 15:55:36 mkarl - * changes for PLinkSpeedUsed - * - * Revision 1.78 2002/09/12 09:39:51 rwahl - * Removed deactivate code for SIRQ overflow event separate for TX/RX. - * - * Revision 1.77 2002/09/09 12:26:37 mkarl - * added handling for Yukon to SkXmTimeStamp - * - * Revision 1.76 2002/08/21 16:41:16 rschmidt - * Added bit GPC_ENA_XC (Enable MDI crossover) in HWCFG_MODE. - * Added forced speed settings in SkGmInitPhyMarv(). - * Added settings of full/half duplex capabilities for YUKON Fiber. - * Editorial changes. - * - * Revision 1.75 2002/08/16 15:12:01 rschmidt - * Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis. - * Added function SkMacHashing() for ADDR-Module. - * Removed functions SkXmClrSrcCheck(), SkXmClrHashAddr() (calls replaced - * with macros). - * Removed functions SkGmGetMuxConfig(). - * Added HWCFG_MODE init for YUKON Fiber. - * Changed initialization of GPHY in SkGmInitPhyMarv(). - * Changed check of parameter in SkXmMacStatistic(). - * Editorial changes. - * - * Revision 1.74 2002/08/12 14:00:17 rschmidt - * Replaced usage of Broadcom PHY Ids with defines. - * Corrected error messages in SkGmMacStatistic(). - * Made SkMacPromiscMode() public for ADDR-Module. - * Editorial changes. - * - * Revision 1.73 2002/08/08 16:26:24 rschmidt - * Improved reset sequence for YUKON in SkGmHardRst() and SkGmInitMac(). - * Replaced XMAC Rx High Watermark init value with SK_XM_RX_HI_WM. - * Editorial changes. - * - * Revision 1.72 2002/07/24 15:11:19 rschmidt - * Fixed wrong placement of parenthesis. - * Editorial changes. - * - * Revision 1.71 2002/07/23 16:05:18 rschmidt - * Added global functions for PHY: SkGePhyRead(), SkGePhyWrite(). - * Fixed Tx Counter Overflow IRQ (Bug ID #10730). - * Editorial changes. - * - * Revision 1.70 2002/07/18 14:27:27 rwahl - * Fixed syntax error. - * - * Revision 1.69 2002/07/17 17:08:47 rwahl - * Fixed check in SkXmMacStatistic(). - * - * Revision 1.68 2002/07/16 07:35:24 rwahl - * Removed check for cleared mib counter in SkGmResetCounter(). - * - * Revision 1.67 2002/07/15 18:35:56 rwahl - * Added SkXmUpdateStats(), SkGmUpdateStats(), SkXmMacStatistic(), - * SkGmMacStatistic(), SkXmResetCounter(), SkGmResetCounter(), - * SkXmOverflowStatus(), SkGmOverflowStatus(). - * Changes to SkXmIrq() & SkGmIrq(): Combined SIRQ Overflow for both - * RX & TX. - * Changes to SkGmInitMac(): call to SkGmResetCounter(). - * Editorial changes. - * - * Revision 1.66 2002/07/15 15:59:30 rschmidt - * Added PHY Address in SkXmPhyRead(), SkXmPhyWrite(). - * Added MIB Clear Counter in SkGmInitMac(). - * Added Duplex and Flow-Control settings. - * Reset all Multicast filtering Hash reg. in SkGmInitMac(). - * Added new function: SkGmGetMuxConfig(). - * Editorial changes. - * - * Revision 1.65 2002/06/10 09:35:39 rschmidt - * Replaced C++ comments (//). - * Added #define VCPU around VCPUwaitTime. - * Editorial changes. - * - * Revision 1.64 2002/06/05 08:41:10 rschmidt - * Added function for XMAC2: SkXmTimeStamp(). - * Added function for YUKON: SkGmSetRxCmd(). - * Changed SkGmInitMac() resp. SkGmHardRst(). - * Fixed wrong variable in SkXmAutoNegLipaXmac() (debug mode). - * SkXmRxTxEnable() replaced by SkMacRxTxEnable(). - * Editorial changes. - * - * Revision 1.63 2002/04/25 13:04:44 rschmidt - * Changes for handling YUKON. - * Use of #ifdef OTHER_PHY to eliminate code for unused Phy types. - * Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced - * by functions SkXmPhyRead(), SkXmPhyWrite(); - * Removed use of PRxCmd to setup XMAC. - * Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res. - * Added setting of XM_RX_DIS_CEXT in SkXmInitMac(). - * Removed status parameter from MAC IRQ handler SkMacIrq(), - * SkXmIrq() and SkGmIrq(). - * SkXmAutoNegLipa...() for ext. Phy replaced by SkMacAutoNegLipaPhy(). - * Added SkMac...() functions to handle both XMAC and GMAC. - * Added functions for YUKON: SkGmHardRst(), SkGmSoftRst(), - * SkGmSetRxTxEn(), SkGmIrq(), SkGmInitMac(), SkGmInitPhyMarv(), - * SkGmAutoNegDoneMarv(), SkGmPhyRead(), SkGmPhyWrite(). - * Changes for V-CPU support. - * Editorial changes. - * - * Revision 1.62 2001/08/06 09:50:14 rschmidt - * Workaround BCOM Errata #1 for the C5 type. - * Editorial changes. - * - * Revision 1.61 2001/02/09 15:40:59 rassmann - * Editorial changes. - * - * Revision 1.60 2001/02/07 15:02:01 cgoos - * Added workaround for Fujitsu switch link down. - * - * Revision 1.59 2001/01/10 09:38:06 cgoos - * Fixed Broadcom C0/A1 Id check for workaround. - * - * Revision 1.58 2000/11/29 11:30:38 cgoos - * Changed DEBUG sections with NW output to xDEBUG - * - * Revision 1.57 2000/11/27 12:40:40 rassmann - * Suppressing preamble after first access to BCom, not before (#10556). - * - * Revision 1.56 2000/11/09 12:32:48 rassmann - * Renamed variables. - * - * Revision 1.55 2000/11/09 11:30:10 rassmann - * WA: Waiting after releasing reset until BCom chip is accessible. - * - * Revision 1.54 2000/10/02 14:10:27 rassmann - * Reading BCOM PHY after releasing reset until it returns a valid value. - * - * Revision 1.53 2000/07/27 12:22:11 gklug - * fix: possible endless loop in XmHardRst. - * - * Revision 1.52 2000/05/22 08:48:31 malthoff - * Fix: #10523 errata valid for all BCOM PHYs. - * - * Revision 1.51 2000/05/17 12:52:18 malthoff - * Fixes BCom link errata (#10523). - * - * Revision 1.50 1999/11/22 13:40:14 cgoos - * Changed license header to GPL. - * - * Revision 1.49 1999/11/22 08:12:13 malthoff - * Add workaround for power consumption feature of BCom C0 chip. - * - * Revision 1.48 1999/11/16 08:39:01 malthoff - * Fix: MDIO preamble suppression is port dependent. - * - * Revision 1.47 1999/08/27 08:55:35 malthoff - * 1000BT: Optimizing MDIO transfer by oppressing MDIO preamble. - * - * Revision 1.46 1999/08/13 11:01:12 malthoff - * Fix for 1000BT: pFlowCtrlMode was not set correctly. - * - * Revision 1.45 1999/08/12 19:18:28 malthoff - * 1000BT Fixes: Do not owerwrite XM_MMU_CMD. - * Do not execute BCOM A1 workaround for B1 chips. - * Fix pause frame setting. - * Always set PHY_B_AC_TX_TST in PHY_BCOM_AUX_CTRL. - * - * Revision 1.44 1999/08/03 15:23:48 cgoos - * Fixed setting of PHY interrupt mask in half duplex mode. - * - * Revision 1.43 1999/08/03 15:22:17 cgoos - * Added some debug output. - * Disabled XMac GP0 interrupt for external PHYs. - * - * Revision 1.42 1999/08/02 08:39:23 malthoff - * BCOM PHY: TX LED: To get the mono flop behaviour it is required - * to set the LED Traffic Mode bit in PHY_BCOM_P_EXT_CTRL. - * - * Revision 1.41 1999/07/30 06:54:31 malthoff - * Add temp. workarounds for the BCOM Phy revision A1. - * - * Revision 1.40 1999/06/01 07:43:26 cgoos - * Changed Link Mode Status in SkXmAutoNegDone... from FULL/HALF to - * AUTOFULL/AUTOHALF. - * - * Revision 1.39 1999/05/19 07:29:51 cgoos - * Changes for 1000Base-T. - * - * Revision 1.38 1999/04/08 14:35:10 malthoff - * Add code for enabling signal detect. Enabling signal detect is disabled. - * - * Revision 1.37 1999/03/12 13:42:54 malthoff - * Add: Jumbo Frame Support. - * Add: Receive modes SK_LENERR_OK_ON/OFF and - * SK_BIG_PK_OK_ON/OFF in SkXmSetRxCmd(). - * - * Revision 1.36 1999/03/08 10:10:55 gklug - * fix: AutoSensing did switch to next mode even if LiPa indicated offline - * - * Revision 1.35 1999/02/22 15:16:41 malthoff - * Remove some compiler warnings. - * - * Revision 1.34 1999/01/22 09:19:59 gklug - * fix: Init DupMode and InitPauseMd are now called in RxTxEnable - * - * Revision 1.33 1998/12/11 15:19:11 gklug - * chg: lipa autoneg stati - * chg: debug messages - * chg: do NOT use spurious XmIrq - * - * Revision 1.32 1998/12/10 11:08:44 malthoff - * bug fix: pAC has been used for IOs in SkXmHardRst(). - * SkXmInitPhy() is also called for the Diag in SkXmInitMac(). - * - * Revision 1.31 1998/12/10 10:39:11 gklug - * fix: do 4 RESETS of the XMAC at the beginning - * fix: dummy read interrupt source register BEFORE initializing the Phy - * add: debug messages - * fix: Linkpartners autoneg capability cannot be shown by TX_PAGE interrupt - * - * Revision 1.30 1998/12/07 12:18:32 gklug - * add: refinement of autosense mode: take into account the autoneg cap of LiPa - * - * Revision 1.29 1998/12/07 07:12:29 gklug - * fix: if page is received the link is down. - * - * Revision 1.28 1998/12/01 10:12:47 gklug - * chg: if spurious IRQ from XMAC encountered, save it - * - * Revision 1.27 1998/11/26 07:33:38 gklug - * add: InitPhy call is now in XmInit function - * - * Revision 1.26 1998/11/18 13:38:24 malthoff - * 'Imsk' is also unused in SkXmAutoNegDone. - * - * Revision 1.25 1998/11/18 13:28:01 malthoff - * Remove unused variable 'Reg' in SkXmAutoNegDone(). - * - * Revision 1.24 1998/11/18 13:18:45 gklug - * add: workaround for xmac errata #1 - * add: detect Link Down also when Link partner requested config - * chg: XMIrq is only used when link is up - * - * Revision 1.23 1998/11/04 07:07:04 cgoos - * Added function SkXmRxTxEnable. - * - * Revision 1.22 1998/10/30 07:35:54 gklug - * fix: serve LinkDown interrupt when link is already down - * - * Revision 1.21 1998/10/29 15:32:03 gklug - * fix: Link Down signaling - * - * Revision 1.20 1998/10/29 11:17:27 gklug - * fix: AutoNegDone bug - * - * Revision 1.19 1998/10/29 10:14:43 malthoff - * Add endainesss comment for reading/writing MAC addresses. - * - * Revision 1.18 1998/10/28 07:48:55 cgoos - * Fix: ASS somtimes signaled although link is up. - * - * Revision 1.17 1998/10/26 07:55:39 malthoff - * Fix in SkXmInitPauseMd(): Pause Mode - * was disabled and not enabled. - * Fix in SkXmAutoNegDone(): Checking Mode bits - * always failed, becaues of some missing braces. - * - * Revision 1.16 1998/10/22 09:46:52 gklug - * fix SysKonnectFileId typo - * - * Revision 1.15 1998/10/21 05:51:37 gklug - * add: para DoLoop to InitPhy function for loopback set-up - * - * Revision 1.14 1998/10/16 10:59:23 malthoff - * Remove Lint warning for dummy reads. - * - * Revision 1.13 1998/10/15 14:01:20 malthoff - * Fix: SkXmAutoNegDone() is (int) but does not return a value. - * - * Revision 1.12 1998/10/14 14:45:04 malthoff - * Remove SKERR_SIRQ_E0xx and SKERR_SIRQ_E0xxMSG by - * SKERR_HWI_Exx and SKERR_HWI_E0xxMSG to be independent - * from the Sirq module. - * - * Revision 1.11 1998/10/14 13:59:01 gklug - * add: InitPhy function - * - * Revision 1.10 1998/10/14 11:20:57 malthoff - * Make SkXmAutoNegDone() public, because it's - * used in diagnostics, too. - * The Link Up event to the RLMT is issued in SkXmIrq(). - * SkXmIrq() is not available in diagnostics. - * Use PHY_READ when reading PHY registers. - * - * Revision 1.9 1998/10/14 05:50:10 cgoos - * Added definition for Para. - * - * Revision 1.8 1998/10/14 05:41:28 gklug - * add: Xmac IRQ - * add: auto-negotiation done function - * - * Revision 1.7 1998/10/09 06:55:20 malthoff - * The configuration of the XMACs Tx Request Threshold - * depends from the drivers port usage now. The port - * usage is configured in GIPortUsage. - * - * Revision 1.6 1998/10/05 07:48:00 malthoff - * minor changes - * - * Revision 1.5 1998/10/01 07:03:54 gklug - * add: dummy function for XMAC ISR - * - * Revision 1.4 1998/09/30 12:37:44 malthoff - * Add SkXmSetRxCmd() and related code. - * - * Revision 1.3 1998/09/28 13:26:40 malthoff - * Add SkXmInitMac(), SkXmInitDupMd(), and SkXmInitPauseMd() - * - * Revision 1.2 1998/09/16 14:34:21 malthoff - * Add SkXmClrExactAddr(), SkXmClrSrcCheck(), - * SkXmClrHashAddr(), SkXmFlushTxFifo(), - * SkXmFlushRxFifo(), and SkXmHardRst(). - * Finish Coding of SkXmSoftRst(). - * The sources may be compiled now. - * - * Revision 1.1 1998/09/04 10:05:56 malthoff - * Created. - * - * - ******************************************************************************/ - #include "h/skdrv1st.h" #include "h/skdrv2nd.h" diff -urN linux-2.4.25/drivers/net/sk_mca.c linux-2.4.26/drivers/net/sk_mca.c --- linux-2.4.25/drivers/net/sk_mca.c 2001-10-16 21:56:29.000000000 -0700 +++ linux-2.4.26/drivers/net/sk_mca.c 2004-04-14 06:05:30.000000000 -0700 @@ -1048,13 +1048,13 @@ block.Mode &= ~LANCE_INIT_PROM; if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */ - memset(block.LAdrF, 8, 0xff); + memset(block.LAdrF, 0xff, sizeof(block.LAdrF)); } else { /* get selected/no multicasts */ struct dev_mc_list *mptr; int code; - memset(block.LAdrF, 8, 0x00); + memset(block.LAdrF, 0, sizeof(block.LAdrF)); for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) { code = GetHash(mptr->dmi_addr); block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7); diff -urN linux-2.4.25/drivers/net/sungem.c linux-2.4.26/drivers/net/sungem.c --- linux-2.4.25/drivers/net/sungem.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/sungem.c 2004-04-14 06:05:30.000000000 -0700 @@ -651,6 +651,7 @@ cluster_start = curr = (gp->rx_new & ~(4 - 1)); count = 0; kick = -1; + wmb(); while (curr != limit) { curr = NEXT_RX(curr); if (++count == 4) { @@ -667,13 +668,16 @@ count = 0; } } - if (kick >= 0) + if (kick >= 0) { + mb(); writel(kick, gp->regs + RXDMA_KICK); + } } static void gem_rx(struct gem *gp) { int entry, drops; + u32 done; if (netif_msg_intr(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", @@ -681,6 +685,7 @@ entry = gp->rx_new; drops = 0; + done = readl(gp->regs + RXDMA_DONE); for (;;) { struct gem_rxd *rxd = &gp->init_block->rxd[entry]; struct sk_buff *skb; @@ -691,6 +696,19 @@ if ((status & RXDCTRL_OWN) != 0) break; + /* When writing back RX descriptor, GEM writes status + * then buffer address, possibly in seperate transactions. + * If we don't wait for the chip to write both, we could + * post a new buffer to this descriptor then have GEM spam + * on the buffer address. We sync on the RX completion + * register to prevent this from happening. + */ + if (entry == done) { + done = readl(gp->regs + RXDMA_DONE); + if (entry == done) + break; + } + skb = gp->rx_skbs[entry]; len = (status & RXDCTRL_BUFSZ) >> 16; @@ -877,6 +895,7 @@ if (gem_intme(entry)) ctrl |= TXDCTRL_INTME; txd->buffer = cpu_to_le64(mapping); + wmb(); txd->control_word = cpu_to_le64(ctrl); entry = NEXT_TX(entry); } else { @@ -916,6 +935,7 @@ txd = &gp->init_block->txd[entry]; txd->buffer = cpu_to_le64(mapping); + wmb(); txd->control_word = cpu_to_le64(this_ctrl | len); if (gem_intme(entry)) @@ -925,6 +945,7 @@ } txd = &gp->init_block->txd[first_entry]; txd->buffer = cpu_to_le64(first_mapping); + wmb(); txd->control_word = cpu_to_le64(ctrl | TXDCTRL_SOF | intme | first_len); } @@ -936,6 +957,7 @@ if (netif_msg_tx_queued(gp)) printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); + mb(); writel(gp->tx_new, gp->regs + TXDMA_KICK); spin_unlock_irq(&gp->lock); @@ -1430,6 +1452,7 @@ gp->rx_skbs[i] = NULL; } rxd->status_word = 0; + wmb(); rxd->buffer = 0; } @@ -1491,6 +1514,7 @@ RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); rxd->buffer = cpu_to_le64(dma_addr); + wmb(); rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp)); skb_reserve(skb, RX_OFFSET); } @@ -1499,8 +1523,10 @@ struct gem_txd *txd = &gb->txd[i]; txd->control_word = 0; + wmb(); txd->buffer = 0; } + wmb(); } /* Must be invoked under gp->lock. */ diff -urN linux-2.4.25/drivers/net/tg3.c linux-2.4.26/drivers/net/tg3.c --- linux-2.4.25/drivers/net/tg3.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/tg3.c 2004-04-14 06:05:30.000000000 -0700 @@ -55,8 +55,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.6" -#define DRV_MODULE_RELDATE "February 3, 2004" +#define DRV_MODULE_VERSION "2.9" +#define DRV_MODULE_RELDATE "March 8, 2004" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -191,6 +191,8 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } }; @@ -212,8 +214,46 @@ } } +static void _tw32_flush(struct tg3 *tp, u32 off, u32 val) +{ + if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { + unsigned long flags; + + spin_lock_irqsave(&tp->indirect_lock, flags); + pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); + spin_unlock_irqrestore(&tp->indirect_lock, flags); + } else { + unsigned long dest = tp->regs + off; + writel(val, dest); + readl(dest); /* always flush PCI write */ + } +} + +static inline void _tw32_rx_mbox(struct tg3 *tp, u32 off, u32 val) +{ + unsigned long mbox = tp->regs + off; + writel(val, mbox); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + readl(mbox); +} + +static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val) +{ + unsigned long mbox = tp->regs + off; + writel(val, mbox); + if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) + writel(val, mbox); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + readl(mbox); +} + +#define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)) +#define tw32_rx_mbox(reg, val) _tw32_rx_mbox(tp, reg, val) +#define tw32_tx_mbox(reg, val) _tw32_tx_mbox(tp, reg, val) + #define tw32(reg,val) tg3_write_indirect_reg32(tp,(reg),(val)) -#define tw32_mailbox(reg, val) writel(((val) & 0xffffffff), tp->regs + (reg)) +#define tw32_f(reg,val) _tw32_flush(tp,(reg),(val)) #define tw16(reg,val) writew(((val) & 0xffff), tp->regs + (reg)) #define tw8(reg,val) writeb(((val) & 0xff), tp->regs + (reg)) #define tr32(reg) readl(tp->regs + (reg)) @@ -300,18 +340,15 @@ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && (orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { - tw32(TG3PCI_CLOCK_CTRL, + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK)); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); - tw32(TG3PCI_CLOCK_CTRL, + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl | (CLOCK_CTRL_ALTCLK)); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); } - tw32(TG3PCI_CLOCK_CTRL, clock_ctrl); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, clock_ctrl); udelay(40); } @@ -323,9 +360,8 @@ int loops, ret; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, + tw32_f(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); - tr32(MAC_MI_MODE); udelay(40); } @@ -337,8 +373,7 @@ MI_COM_REG_ADDR_MASK); frame_val |= (MI_COM_CMD_READ | MI_COM_START); - tw32(MAC_MI_COM, frame_val); - tr32(MAC_MI_COM); + tw32_f(MAC_MI_COM, frame_val); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { @@ -359,8 +394,7 @@ } if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } @@ -373,9 +407,8 @@ int loops, ret; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, + tw32_f(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); - tr32(MAC_MI_MODE); udelay(40); } @@ -386,8 +419,7 @@ frame_val |= (val & MI_COM_DATA_MASK); frame_val |= (MI_COM_CMD_WRITE | MI_COM_START); - tw32(MAC_MI_COM, frame_val); - tr32(MAC_MI_COM); + tw32_f(MAC_MI_COM, frame_val); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { @@ -405,8 +437,7 @@ ret = 0; if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } @@ -655,6 +686,18 @@ return err; out: + if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f); + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa); + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0323); + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); + } + if (tp->tg3_flags2 & TG3_FLG2_PHY_5704_A0_BUG) { + tg3_writephy(tp, 0x1c, 0x8d68); + tg3_writephy(tp, 0x1c, 0x8d68); + } tg3_phy_set_wirespeed(tp); return 0; } @@ -677,45 +720,41 @@ (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } else { if (tp_peer != tp && (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) return; - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } } else { @@ -725,27 +764,24 @@ (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) return; - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1)); - tr32(GRC_LOCAL_CTRL); udelay(100); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1)); - tr32(GRC_LOCAL_CTRL); udelay(100); } } } -static int tg3_setup_phy(struct tg3 *); +static int tg3_setup_phy(struct tg3 *, int); static int tg3_set_power_state(struct tg3 *tp, int state) { @@ -771,8 +807,7 @@ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - tr32(GRC_LOCAL_CTRL); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); return 0; @@ -813,7 +848,7 @@ tp->link_config.speed = SPEED_10; tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps); @@ -839,12 +874,10 @@ (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; - tw32(MAC_MODE, mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, mac_mode); udelay(100); - tw32(MAC_RX_MODE, RX_MODE_ENABLE); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, RX_MODE_ENABLE); udelay(10); } @@ -857,10 +890,9 @@ base_val |= (CLOCK_CTRL_RXCLK_DISABLE | CLOCK_CTRL_TXCLK_DISABLE); - tw32(TG3PCI_CLOCK_CTRL, base_val | + tw32_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | CLOCK_CTRL_PWRDOWN_PLL133); - tr32(TG3PCI_CLOCK_CTRL); udelay(40); } else { u32 newbits1, newbits2; @@ -879,12 +911,10 @@ newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; } - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1); udelay(40); - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2); udelay(40); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { @@ -899,8 +929,8 @@ newbits3 = CLOCK_CTRL_44MHZ_CORE; } - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits3); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, + tp->pci_clock_ctrl | newbits3); udelay(40); } } @@ -1014,7 +1044,7 @@ }; } -static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link) +static int tg3_phy_copper_begin(struct tg3 *tp) { u32 new_adv; int i; @@ -1132,7 +1162,7 @@ tg3_readphy(tp, MII_BMCR, &orig_bmcr); if (bmcr != orig_bmcr) { tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK); - for (i = 0; i < 15000; i++) { + for (i = 0; i < 1500; i++) { u32 tmp; udelay(10); @@ -1151,27 +1181,6 @@ BMCR_ANENABLE | BMCR_ANRESTART); } - if (wait_for_link) { - tp->link_config.active_speed = SPEED_INVALID; - tp->link_config.active_duplex = DUPLEX_INVALID; - for (i = 0; i < 300000; i++) { - u32 tmp; - - udelay(10); - tg3_readphy(tp, MII_BMSR, &tmp); - tg3_readphy(tp, MII_BMSR, &tmp); - if (!(tmp & BMSR_LSTATUS)) - continue; - - tg3_readphy(tp, MII_TG3_AUX_STAT, &tmp); - tg3_aux_stat_to_speed_duplex(tp, tmp, - &tp->link_config.active_speed, - &tp->link_config.active_duplex); - } - if (tp->link_config.active_speed == SPEED_INVALID) - return -EINVAL; - } - return 0; } @@ -1202,7 +1211,7 @@ return err; } -static int tg3_setup_copper_phy(struct tg3 *tp) +static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) { int current_link_up; u32 bmsr, dummy; @@ -1210,15 +1219,17 @@ u8 current_duplex; int i, err; - tw32(MAC_STATUS, + tw32(MAC_EVENT, 0); + + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | - MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); + MAC_STATUS_CFG_CHANGED | + MAC_STATUS_MI_COMPLETION | + MAC_STATUS_LNKSTATE_CHANGED)); udelay(40); tp->mi_mode = MAC_MI_MODE_BASE; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); @@ -1233,8 +1244,10 @@ tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); if (!(bmsr & BMSR_LSTATUS)) - tg3_phy_reset(tp, 1); + force_reset = 1; } + if (force_reset) + tg3_phy_reset(tp, 1); if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); @@ -1370,7 +1383,7 @@ if (current_link_up == 0) { u32 tmp; - tg3_phy_copper_begin(tp, 0); + tg3_phy_copper_begin(tp); tg3_readphy(tp, MII_BMSR, &tmp); tg3_readphy(tp, MII_BMSR, &tmp); @@ -1410,24 +1423,19 @@ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 && tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) { tp->mi_mode |= MAC_MI_MODE_AUTO_POLL; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); } - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - if (tp->tg3_flags & - (TG3_FLAG_USE_LINKCHG_REG | - TG3_FLAG_POLL_SERDES)) { + if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | TG3_FLAG_POLL_SERDES)) { /* Polled via timer. */ - tw32(MAC_EVENT, 0); + tw32_f(MAC_EVENT, 0); } else { - tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); } - tr32(MAC_EVENT); udelay(40); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && @@ -1436,10 +1444,9 @@ ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) || (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) { udelay(120); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, @@ -1601,8 +1608,7 @@ ap->txconfig = 0; tw32(MAC_TX_AUTO_NEG, 0); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ret = ANEG_TIMER_ENAB; @@ -1627,8 +1633,7 @@ ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1); tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_ABILITY_DETECT; @@ -1644,8 +1649,7 @@ ap->txconfig |= ANEG_CFG_ACK; tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_ACK_DETECT; @@ -1731,8 +1735,7 @@ case ANEG_STATE_IDLE_DETECT_INIT: ap->link_time = ap->cur_time; tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); ap->state = ANEG_STATE_IDLE_DETECT; @@ -1773,7 +1776,7 @@ return ret; } -static int tg3_setup_fiber_phy(struct tg3 *tp) +static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) { u32 orig_pause_cfg; u16 orig_active_speed; @@ -1789,8 +1792,7 @@ tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); /* Reset when initting first time or we have a link. */ @@ -1838,10 +1840,9 @@ /* Enable link change interrupt unless serdes polling. */ if (!(tp->tg3_flags & TG3_FLAG_POLL_SERDES)) - tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); + tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); else - tw32(MAC_EVENT, 0); - tr32(MAC_EVENT); + tw32_f(MAC_EVENT, 0); udelay(40); current_link_up = 0; @@ -1859,12 +1860,10 @@ tw32(MAC_TX_AUTO_NEG, 0); tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; - tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); udelay(40); - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); udelay(40); aninfo.state = ANEG_STATE_UNKNOWN; @@ -1880,8 +1879,7 @@ } tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); if (status == ANEG_DONE && @@ -1905,10 +1903,9 @@ } for (i = 0; i < 60; i++) { udelay(20); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | @@ -1926,8 +1923,7 @@ } tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); tp->hw_status->status = @@ -1936,10 +1932,9 @@ for (i = 0; i < 100; i++) { udelay(20); - tw32(MAC_STATUS, + tw32_f(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - tr32(MAC_STATUS); udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | @@ -1975,12 +1970,10 @@ } if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); udelay(40); if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); } } @@ -1988,14 +1981,14 @@ return 0; } -static int tg3_setup_phy(struct tg3 *tp) +static int tg3_setup_phy(struct tg3 *tp, int force_reset) { int err; if (tp->phy_id == PHY_ID_SERDES) { - err = tg3_setup_fiber_phy(tp); + err = tg3_setup_fiber_phy(tp, force_reset); } else { - err = tg3_setup_copper_phy(tp); + err = tg3_setup_copper_phy(tp, force_reset); } if (tp->link_config.active_speed == SPEED_1000 && @@ -2324,25 +2317,19 @@ /* ACK the status ring. */ tp->rx_rcb_ptr = rx_rcb_ptr; - tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, + tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE(tp))); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW); /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE; - tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, + tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW); } if (work_mask & RXD_OPAQUE_RING_JUMBO) { sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE; - tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, + tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW); } return received; @@ -2364,7 +2351,7 @@ if (sblk->status & SD_STATUS_LINK_CHG) { sblk->status = SD_STATUS_UPDATED | (sblk->status & ~SD_STATUS_LINK_CHG); - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } } @@ -2794,32 +2781,17 @@ /* Packets are ready, update Tx producer idx local and on card. */ if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); - if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) - tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW); } else { /* First, make sure tg3 sees last descriptor fully * in SRAM. */ if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW); + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); - tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + + tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); - if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) - tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW), entry); - - /* Now post the mailbox write itself. */ - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW); } tp->tx_prod = entry; @@ -2964,11 +2936,8 @@ * the double-write bug tests. */ if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { - tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDHOST_PROD_IDX_0 + - TG3_64BIT_REG_LOW); } else { /* First, make sure tg3 sees last descriptor fully * in SRAM. @@ -2977,13 +2946,8 @@ tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); - tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + + tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); - - /* Now post the mailbox write itself. */ - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + - TG3_64BIT_REG_LOW); } tp->tx_prod = entry; @@ -3337,8 +3301,7 @@ val = tr32(ofs); val &= ~enable_bit; - tw32(ofs, val); - tr32(ofs); + tw32_f(ofs, val); for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); @@ -3365,8 +3328,7 @@ tg3_disable_ints(tp); tp->rx_mode &= ~RX_MODE_ENABLE; - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); err = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE); @@ -3387,13 +3349,11 @@ goto out; tp->mac_mode &= ~MAC_MODE_TDE_ENABLE; - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); tp->tx_mode &= ~TX_MODE_ENABLE; - tw32(MAC_TX_MODE, tp->tx_mode); - tr32(MAC_TX_MODE); + tw32_f(MAC_TX_MODE, tp->tx_mode); for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); @@ -3419,7 +3379,10 @@ if (err) goto out; - memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + if (tp->hw_status) + memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); + if (tp->hw_stats) + memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats)); out: return err; @@ -3716,8 +3679,7 @@ } tw32(offset + CPU_STATE, 0xffffffff); - tw32(offset + CPU_MODE, CPU_MODE_HALT); - tr32(offset + CPU_MODE); + tw32_f(offset + CPU_MODE, CPU_MODE_HALT); udelay(10); } else { for (i = 0; i < 10000; i++) { @@ -3840,20 +3802,14 @@ /* Now startup only the RX cpu. */ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); - tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); + tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_PC); for (i = 0; i < 5; i++) { if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR) break; tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT); - tw32(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); - - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_PC); - + tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR); udelay(1000); } if (i >= 5) { @@ -3864,10 +3820,7 @@ return -ENODEV; } tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff); - tw32(RX_CPU_BASE + CPU_MODE, 0x00000000); - - /* Flush posted writes. */ - tr32(RX_CPU_BASE + CPU_MODE); + tw32_f(RX_CPU_BASE + CPU_MODE, 0x00000000); return 0; } @@ -4425,20 +4378,14 @@ /* Now startup the cpu. */ tw32(cpu_base + CPU_STATE, 0xffffffff); - tw32(cpu_base + CPU_PC, info.text_base); + tw32_f(cpu_base + CPU_PC, info.text_base); - /* Flush posted writes. */ - tr32(cpu_base + CPU_PC); for (i = 0; i < 5; i++) { if (tr32(cpu_base + CPU_PC) == info.text_base) break; tw32(cpu_base + CPU_STATE, 0xffffffff); tw32(cpu_base + CPU_MODE, CPU_MODE_HALT); - tw32(cpu_base + CPU_PC, info.text_base); - - /* Flush posted writes. */ - tr32(cpu_base + CPU_PC); - + tw32_f(cpu_base + CPU_PC, info.text_base); udelay(1000); } if (i >= 5) { @@ -4449,11 +4396,7 @@ return -ENODEV; } tw32(cpu_base + CPU_STATE, 0xffffffff); - tw32(cpu_base + CPU_MODE, 0x00000000); - - /* Flush posted writes. */ - tr32(cpu_base + CPU_MODE); - + tw32_f(cpu_base + CPU_MODE, 0x00000000); return 0; } @@ -4500,9 +4443,6 @@ struct tg3 *tp = dev->priv; struct sockaddr *addr = p; - if (netif_running(dev)) - return -EBUSY; - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&tp->lock); @@ -4562,10 +4502,9 @@ NIC_SRAM_FIRMWARE_MBOX_MAGIC1); if (tp->phy_id == PHY_ID_SERDES) { tp->mac_mode = MAC_MODE_PORT_MODE_TBI; - tw32(MAC_MODE, tp->mac_mode); + tw32_f(MAC_MODE, tp->mac_mode); } else - tw32(MAC_MODE, 0); - tr32(MAC_MODE); + tw32_f(MAC_MODE, 0); udelay(40); /* Wait for firmware initialization to complete. */ @@ -4595,8 +4534,7 @@ * other revision. */ tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT; - tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); - tr32(TG3PCI_CLOCK_CTRL); + tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl); if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { @@ -4793,9 +4731,7 @@ tp->tx_prod = 0; tp->tx_cons = 0; tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); + tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, @@ -4822,9 +4758,7 @@ } tp->rx_rcb_ptr = 0; - tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW); + tw32_rx_mbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, tp->rx_rcb_mapping, @@ -4833,19 +4767,13 @@ 0); tp->rx_std_ptr = tp->rx_pending; - tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, + tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_std_ptr); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW); - if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) - tp->rx_jumbo_ptr = tp->rx_jumbo_pending; - else - tp->rx_jumbo_ptr = 0; - tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, + tp->rx_jumbo_ptr = (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) ? + tp->rx_jumbo_pending : 0; + tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_jumbo_ptr); - if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) - tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW); /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp); @@ -4950,24 +4878,21 @@ tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; - tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); udelay(40); tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); - tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - tr32(GRC_LOCAL_CTRL); + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl); udelay(100); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); tr32(MAILBOX_INTERRUPT_0); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) { - tw32(DMAC_MODE, DMAC_MODE_ENABLE); - tr32(DMAC_MODE); + tw32_f(DMAC_MODE, DMAC_MODE_ENABLE); udelay(40); } @@ -4980,8 +4905,7 @@ (tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0 && !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) val |= WDMAC_MODE_RX_ACCEL; - tw32(WDMAC_MODE, val); - tr32(WDMAC_MODE); + tw32_f(WDMAC_MODE, val); udelay(40); if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) { @@ -4999,8 +4923,7 @@ tw32(TG3PCI_X_CAPS, val); } - tw32(RDMAC_MODE, rdmac_mode); - tr32(RDMAC_MODE); + tw32_f(RDMAC_MODE, rdmac_mode); udelay(40); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); @@ -5029,13 +4952,11 @@ #endif tp->tx_mode = TX_MODE_ENABLE; - tw32(MAC_TX_MODE, tp->tx_mode); - tr32(MAC_TX_MODE); + tw32_f(MAC_TX_MODE, tp->tx_mode); udelay(100); tp->rx_mode = RX_MODE_ENABLE; - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); if (tp->link_config.phy_is_low_power) { @@ -5046,19 +4967,16 @@ } tp->mi_mode = MAC_MI_MODE_BASE; - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); tw32(MAC_LED_CTRL, 0); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); if (tp->phy_id == PHY_ID_SERDES) { - tw32(MAC_RX_MODE, RX_MODE_RESET); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, RX_MODE_RESET); udelay(10); } - tw32(MAC_RX_MODE, tp->rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) @@ -5067,10 +4985,9 @@ /* Prevent chip from dropping frames when flow control * is enabled. */ - tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2); - tr32(MAC_LOW_WMARK_MAX_RX_FRAME); + tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, 2); - err = tg3_setup_phy(tp); + err = tg3_setup_phy(tp, 1); if (err) return err; @@ -5252,7 +5169,7 @@ phy_event = 1; if (phy_event) - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) { u32 mac_stat = tr32(MAC_STATUS); int need_setup = 0; @@ -5266,15 +5183,13 @@ need_setup = 1; } if (need_setup) { - tw32(MAC_MODE, + tw32_f(MAC_MODE, (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK)); - tr32(MAC_MODE); udelay(40); - tw32(MAC_MODE, tp->mac_mode); - tr32(MAC_MODE); + tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - tg3_setup_phy(tp); + tg3_setup_phy(tp, 0); } } @@ -5827,8 +5742,7 @@ if (rx_mode != tp->rx_mode) { tp->rx_mode = rx_mode; - tw32(MAC_RX_MODE, rx_mode); - tr32(MAC_RX_MODE); + tw32_f(MAC_RX_MODE, rx_mode); udelay(10); } } @@ -5954,7 +5868,7 @@ struct tg3 *tp = dev->priv; if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) || - tp->link_config.phy_is_low_power) + tp->link_config.phy_is_low_power) return -EAGAIN; spin_lock_irq(&tp->lock); @@ -5970,7 +5884,7 @@ tp->link_config.duplex = cmd->duplex; } - tg3_setup_phy(tp); + tg3_setup_phy(tp, 1); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); @@ -6295,7 +6209,7 @@ if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) return; - tw32(GRC_EEPROM_ADDR, + tw32_f(GRC_EEPROM_ADDR, (EEPROM_ADDR_FSM_RESET | (EEPROM_DEFAULT_CLOCK_PERIOD << EEPROM_ADDR_CLKPERD_SHIFT))); @@ -6305,9 +6219,8 @@ udelay(10); /* Enable seeprom accesses. */ - tw32(GRC_LOCAL_CTRL, + tw32_f(GRC_LOCAL_CTRL, tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM); - tr32(GRC_LOCAL_CTRL); udelay(100); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && @@ -6916,6 +6829,12 @@ (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1))) tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED; + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX || + GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX) + tp->tg3_flags2 |= TG3_FLG2_PHY_ADC_BUG; + if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) + tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; + /* Only 5701 and later support tagged irq status mode. * Also, 5788 chips cannot use tagged irq status. * @@ -6930,8 +6849,7 @@ tp->coalesce_mode |= HOSTCC_MODE_32BYTE; /* Initialize MAC MI mode, polling disabled. */ - tw32(MAC_MI_MODE, tp->mi_mode); - tr32(MAC_MI_MODE); + tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(40); /* Initialize data/descriptor byte/word swapping. */ @@ -7207,14 +7125,12 @@ if (to_device) { test_desc.cqid_sqid = (13 << 8) | 2; - tw32(RDMAC_MODE, RDMAC_MODE_ENABLE); - tr32(RDMAC_MODE); + tw32_f(RDMAC_MODE, RDMAC_MODE_ENABLE); udelay(40); } else { test_desc.cqid_sqid = (16 << 8) | 7; - tw32(WDMAC_MODE, WDMAC_MODE_ENABLE); - tr32(WDMAC_MODE); + tw32_f(WDMAC_MODE, WDMAC_MODE_ENABLE); udelay(40); } test_desc.flags = 0x00000005; @@ -7415,17 +7331,18 @@ break; } +#if 0 /* validate data reached card RAM correctly. */ for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) { u32 val; tg3_read_mem(tp, 0x2100 + (i*4), &val); - if (val != p[i]) { - printk( KERN_ERR " tg3_test_dma() Card buffer currupted on write! (%d != %d)\n", val, i); + if (le32_to_cpu(val) != p[i]) { + printk(KERN_ERR " tg3_test_dma() Card buffer corrupted on write! (%d != %d)\n", val, i); /* ret = -ENODEV here? */ } p[i] = 0; } - +#endif /* Now read it back. */ ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0); if (ret) { @@ -7740,6 +7657,18 @@ goto err_out_iounmap; } + /* + * Reset chip in case UNDI or EFI driver did not shutdown + * DMA self test will enable WDMAC and we'll see (spurious) + * pending DMA on the PCI bus at that point. + */ + if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || + (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + pci_save_state(tp->pdev, tp->pci_cfg_state); + tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); + tg3_halt(tp); + } + err = tg3_test_dma(tp); if (err) { printk(KERN_ERR PFX "DMA engine test failed, aborting.\n"); diff -urN linux-2.4.25/drivers/net/tg3.h linux-2.4.26/drivers/net/tg3.h --- linux-2.4.25/drivers/net/tg3.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/tg3.h 2004-04-14 06:05:30.000000000 -0700 @@ -129,6 +129,9 @@ #define CHIPREV_5700_BX 0x71 #define CHIPREV_5700_CX 0x72 #define CHIPREV_5701_AX 0x00 +#define CHIPREV_5703_AX 0x10 +#define CHIPREV_5704_AX 0x20 +#define CHIPREV_5704_BX 0x21 #define GET_METAL_REV(CHIP_REV_ID) ((CHIP_REV_ID) & 0xff) #define METAL_REV_A0 0x00 #define METAL_REV_A1 0x01 @@ -1889,7 +1892,11 @@ #define TG3_FLAG_ENABLE_ASF 0x00000020 #define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040 #define TG3_FLAG_POLL_SERDES 0x00000080 +#if defined(CONFIG_X86) #define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 +#else +#define TG3_FLAG_MBOX_WRITE_REORDER 0 /* disables code too */ +#endif #define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 #define TG3_FLAG_WOL_SPEED_100MB 0x00000400 #define TG3_FLAG_WOL_ENABLE 0x00000800 @@ -1920,6 +1927,8 @@ #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 #define TG3_FLG2_TSO_CAPABLE 0x00000020 +#define TG3_FLG2_PHY_ADC_BUG 0x00000040 +#define TG3_FLG2_PHY_5704_A0_BUG 0x00000080 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 diff -urN linux-2.4.25/drivers/net/tulip/tulip_core.c linux-2.4.26/drivers/net/tulip/tulip_core.c --- linux-2.4.25/drivers/net/tulip/tulip_core.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/tulip/tulip_core.c 2004-04-14 06:05:30.000000000 -0700 @@ -579,7 +579,7 @@ dev->if_port = 2 - dev->if_port; } else dev->if_port = 0; - else + else if (dev->if_port != 0 || (csr12 & 0x0004) != 0) dev->if_port = 1; tulip_select_media(dev, 0); } diff -urN linux-2.4.25/drivers/net/typhoon-firmware.h linux-2.4.26/drivers/net/typhoon-firmware.h --- linux-2.4.25/drivers/net/typhoon-firmware.h 2003-06-13 07:51:35.000000000 -0700 +++ linux-2.4.26/drivers/net/typhoon-firmware.h 2004-04-14 06:05:30.000000000 -0700 @@ -1,7 +1,7 @@ /* - * Copyright 1999-2002 3Com Corporation. All Rights Reserved. + * Copyright 1999-2003 3Com Corporation. All Rights Reserved. * - * Redistribution and use in source and binary forms of the 3CR990img.h + * Redistribution and use in source and binary forms of the 3c990img.h * microcode software are permitted provided that the following conditions * are met: * 1. Redistribution of source code must retain the above copyright @@ -23,385 +23,394 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3CR990img.h + * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3c990img.h * MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY * IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN - * COMBINATION WITH THE 3CR990img.h microcode SOFTWARE + * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE */ + const u8 typhoon_firmware_image[] = { 0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00, -0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x40, 0x01, 0x00, 0x00, -0x6c, 0xef, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, -0x05, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, -0x02, 0x00, 0x00, 0xea, 0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, -0xa5, 0x14, 0x00, 0xea, 0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, -0x00, 0x10, 0x0f, 0xe1, 0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, -0xfe, 0xff, 0xff, 0xea, 0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, -0x01, 0x00, 0x50, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, -0x00, 0xa0, 0xa0, 0xe1, 0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, -0xa8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, -0x00, 0x00, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, -0x01, 0x00, 0x80, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, -0x00, 0xf0, 0x21, 0xe1, 0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, -0x00, 0xf0, 0x21, 0xe1, 0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, -0x00, 0xf0, 0x21, 0xe1, 0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, -0x00, 0xf0, 0x21, 0xe1, 0x6c, 0xd0, 0x9f, 0xe5, 0x7b, 0x14, 0x00, 0xeb, -0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, -0x60, 0x00, 0x9f, 0xe5, 0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, -0xdb, 0xff, 0xff, 0xeb, 0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, -0x00, 0x20, 0xa0, 0xe3, 0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, -0x54, 0x10, 0x9f, 0xe5, 0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, -0x0b, 0xf0, 0xa0, 0xe1, 0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, -0xd4, 0xff, 0xff, 0xeb, 0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, -0xc6, 0xff, 0xff, 0xea, 0xbd, 0x20, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, -0x1c, 0x00, 0x10, 0x00, 0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, -0xfc, 0x3f, 0x00, 0x80, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, -0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, 0xa8, 0xbc, 0x00, 0x00, -0x24, 0xab, 0x20, 0x40, 0x34, 0x29, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, -0x6d, 0xc8, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xd8, 0x56, 0x00, 0x00, 0x06, 0x24, 0x00, 0x00, -0x60, 0x01, 0xff, 0xff, 0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x00, 0x25, -0xe0, 0x6b, 0x00, 0x28, 0x1d, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, -0x37, 0xfd, 0xe1, 0x6b, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x14, 0xd0, -0x38, 0x01, 0x0d, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, -0x41, 0x6b, 0x80, 0x29, 0x0b, 0xd2, 0x01, 0x31, 0x41, 0x63, 0xe0, 0x6b, -0xc1, 0x69, 0xc0, 0x46, 0xe1, 0x63, 0x39, 0x07, 0x41, 0x60, 0xc7, 0x62, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x1c, 0xfa, 0xe7, 0x00, 0x00, -0x28, 0x17, 0x00, 0x80, 0xee, 0x05, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, -0x02, 0x49, 0xca, 0x6b, 0xc0, 0x46, 0xc2, 0x61, 0xc8, 0x63, 0x70, 0x47, -0x28, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, -0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, -0x00, 0x10, 0xa0, 0xe1, 0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, -0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, -0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, -0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, +0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbf, 0xcd, 0x57, 0xc3, +0xba, 0x01, 0x2c, 0xe8, 0xcd, 0xef, 0xa9, 0xd9, 0x6f, 0xbb, 0x76, 0x2f, +0x86, 0x49, 0xac, 0x1b, 0x40, 0x01, 0x00, 0x00, 0x8a, 0xe4, 0x00, 0x00, +0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea, +0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, +0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc0, 0x14, 0x00, 0xea, +0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1, +0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea, +0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1, +0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1, +0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5, +0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5, +0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3, +0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x6c, 0xd0, 0x9f, 0xe5, 0x96, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3, +0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5, +0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb, +0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3, +0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5, +0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1, +0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb, +0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea, +0x01, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00, +0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80, +0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, +0xad, 0xde, 0xad, 0xde, 0x5c, 0xbc, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40, +0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0x8d, 0xd2, 0x21, 0x40, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x44, 0x57, 0x00, 0x00, 0x71, 0xaf, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff, +0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x00, 0x25, 0x20, 0x68, 0x00, 0x28, +0x1d, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x71, 0xfd, 0x21, 0x68, +0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x14, 0xd0, 0x38, 0x01, 0x0d, 0x49, +0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29, +0x0b, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x20, 0x68, 0xc1, 0x69, 0xc0, 0x46, +0x21, 0x60, 0x39, 0x07, 0x41, 0x60, 0xc7, 0x62, 0xb0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x28, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0xe8, 0x17, 0x00, 0x80, +0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, +0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47, +0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, +0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1, +0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, -0x40, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, -0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, -0x00, 0xf0, 0x21, 0xe1, 0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, -0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, +0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, +0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, -0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, -0x91, 0x00, 0x00, 0xe0, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, -0x01, 0x00, 0x80, 0xe0, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, -0x64, 0x28, 0x04, 0xd3, 0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, -0x03, 0xe0, 0x38, 0x63, 0x04, 0x49, 0x05, 0xf0, 0xc1, 0xfa, 0x78, 0x63, -0xb8, 0x63, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x88, 0x13, 0x00, 0x00, 0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, -0x64, 0x2f, 0x03, 0xd2, 0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, -0x10, 0x1c, 0x80, 0xbc, 0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, -0xbb, 0x42, 0x05, 0xd2, 0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, -0xc8, 0x63, 0xf1, 0xe7, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, -0x04, 0x48, 0xc1, 0x6b, 0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, -0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, -0x90, 0xb5, 0x07, 0x1c, 0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, -0x0b, 0xd2, 0xb9, 0x6e, 0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, -0x91, 0x42, 0x07, 0xd2, 0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, -0x21, 0x64, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, -0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xe7, 0xfd, 0x38, 0x1c, -0x02, 0xf0, 0xa4, 0xfa, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, -0xc8, 0x72, 0x05, 0x49, 0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, -0x8a, 0x6d, 0x12, 0x18, 0x8a, 0x65, 0xe4, 0xe7, 0xe8, 0x0d, 0x00, 0x80, -0x78, 0x2a, 0x00, 0x80, 0x10, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, -0xc0, 0x6d, 0x02, 0x23, 0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, -0x03, 0xd0, 0xd1, 0x63, 0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, -0x07, 0x68, 0x7b, 0x1c, 0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, -0xf3, 0xe7, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, -0x60, 0x01, 0x00, 0x80, 0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, -0x10, 0x18, 0x0a, 0x04, 0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, -0x01, 0x0c, 0x05, 0xd0, 0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, -0x01, 0x0c, 0xf9, 0xd1, 0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, -0x00, 0x22, 0x00, 0x29, 0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f, +0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, +0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3, +0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1, +0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3, +0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0, +0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0, +0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3, +0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63, +0x04, 0x49, 0x05, 0xf0, 0xf7, 0xfa, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00, +0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2, +0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc, +0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2, +0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7, +0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b, +0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80, +0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, +0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e, +0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2, +0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, +0x38, 0x6b, 0x02, 0xf0, 0x23, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xde, 0xfa, +0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49, +0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18, +0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, +0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23, +0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63, +0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c, +0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00, +0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80, +0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04, +0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0, +0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1, +0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29, +0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f, 0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b, -0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, -0x00, 0x88, 0x00, 0x06, 0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, -0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, -0x10, 0x04, 0x00, 0x0c, 0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, -0xc7, 0x89, 0xfb, 0x18, 0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, -0x40, 0x7a, 0x00, 0x02, 0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, -0x00, 0x0c, 0x3b, 0x0c, 0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, -0x11, 0x1c, 0xff, 0xf7, 0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, -0xb0, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, -0x82, 0x68, 0x1a, 0x40, 0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, -0x93, 0x69, 0x01, 0x33, 0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, -0x00, 0x68, 0x1c, 0x18, 0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, -0xac, 0xff, 0xc0, 0x43, 0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, -0x82, 0x68, 0x1a, 0x40, 0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, -0x52, 0x09, 0x0e, 0xd3, 0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, -0xcb, 0x68, 0x02, 0x68, 0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, -0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, -0x90, 0xb5, 0x80, 0x23, 0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, -0x15, 0xd0, 0x4a, 0x68, 0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, -0x01, 0x33, 0xd3, 0x61, 0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, -0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, -0x00, 0x28, 0x00, 0xd1, 0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, -0xff, 0xff, 0x00, 0x00, 0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, -0x38, 0x69, 0xb9, 0x68, 0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, -0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, -0x04, 0x1c, 0xb8, 0x68, 0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, -0x0c, 0xd2, 0x2a, 0x68, 0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, -0x05, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, -0x26, 0xff, 0x04, 0x1c, 0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, -0x1a, 0xd3, 0xb8, 0x6a, 0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, -0xed, 0xf8, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, -0x20, 0x23, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, -0x01, 0x63, 0x07, 0xe0, 0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, -0xb9, 0x61, 0x41, 0x6a, 0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, -0xb8, 0x6b, 0x41, 0x09, 0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, -0x39, 0x30, 0x00, 0x7b, 0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, -0x53, 0xf8, 0x01, 0x1c, 0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69, +0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06, +0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, +0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, +0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18, +0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02, +0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c, +0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7, +0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40, +0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33, +0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18, +0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, +0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40, +0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3, +0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68, +0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68, +0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23, +0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68, +0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61, +0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, +0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1, +0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, +0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68, +0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04, +0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68, +0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68, +0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43, +0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c, +0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a, +0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43, +0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69, +0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0, +0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a, +0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09, +0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b, +0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c, +0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0, -0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, -0xb9, 0x61, 0xc1, 0x6a, 0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, -0xb8, 0x6b, 0x81, 0x09, 0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, -0x39, 0x30, 0x00, 0x7b, 0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, -0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, -0x05, 0x04, 0x2d, 0x0c, 0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, -0x1f, 0xf8, 0x00, 0x28, 0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, -0x98, 0x42, 0x07, 0xd0, 0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, -0x60, 0x6b, 0x01, 0x30, 0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, -0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, -0x00, 0x20, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, -0xff, 0xff, 0x00, 0x00, 0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, -0xe0, 0x6b, 0x61, 0x6c, 0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, -0x00, 0x20, 0x8a, 0x08, 0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, -0x9f, 0x58, 0x03, 0xae, 0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, -0xf7, 0xd8, 0x60, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, -0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, -0xff, 0xf7, 0x87, 0xfe, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, -0xff, 0xf7, 0x6d, 0xfe, 0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, -0x61, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, -0xc0, 0x46, 0x01, 0x91, 0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, -0x0c, 0xd2, 0xa2, 0x6a, 0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, -0x2f, 0xf8, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, -0x50, 0xfe, 0x07, 0x1c, 0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, -0x08, 0x18, 0x69, 0x8a, 0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, -0xa1, 0x6c, 0x62, 0x6c, 0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, -0x12, 0x0a, 0x11, 0x43, 0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, -0x05, 0xd0, 0x08, 0x04, 0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, -0xf9, 0xd1, 0x38, 0x1c, 0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, -0x00, 0x0c, 0x7f, 0xb0, 0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xb0, 0xb4, 0x00, 0x22, 0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, -0xdc, 0x00, 0x47, 0x18, 0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, -0xff, 0x00, 0x80, 0x08, 0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, -0x4d, 0x1e, 0x02, 0xc8, 0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, -0x09, 0xd0, 0x0c, 0x04, 0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, -0x02, 0xc8, 0x1c, 0x1c, 0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, -0x08, 0x1c, 0xf8, 0x40, 0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, -0x42, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, -0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, -0x70, 0x47, 0x00, 0x00, 0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, -0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23, +0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a, +0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09, +0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b, +0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23, +0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c, +0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28, +0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0, +0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30, +0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43, +0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, +0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c, +0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08, +0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae, +0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a, +0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, +0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe, +0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe, +0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23, +0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91, +0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a, +0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43, +0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c, +0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a, +0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c, +0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43, +0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04, +0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c, +0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0, +0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22, +0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18, +0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08, +0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8, +0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04, +0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c, +0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40, +0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c, +0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, +0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, +0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18, +0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58, -0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, -0x01, 0x30, 0x04, 0x28, 0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, -0x09, 0x0b, 0x07, 0x48, 0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, -0x02, 0xd0, 0x38, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, -0x28, 0x03, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xe8, 0x0d, 0x00, 0x80, -0x98, 0xb4, 0x14, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, -0xc0, 0x58, 0x07, 0x03, 0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, -0x12, 0x0b, 0x11, 0x48, 0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, -0xe4, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, -0xcc, 0x00, 0x01, 0x21, 0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, -0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, -0x18, 0x1a, 0x84, 0x42, 0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, -0x55, 0x55, 0x55, 0x55, 0xa0, 0x03, 0x00, 0x80, 0xa8, 0x03, 0x00, 0x80, -0x88, 0x03, 0x00, 0x80, 0x98, 0x03, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, -0x00, 0xd0, 0x01, 0x3a, 0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, -0xc0, 0x46, 0x3b, 0x60, 0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, -0x08, 0x32, 0x10, 0x4b, 0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, -0x12, 0x58, 0x0f, 0x4b, 0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, -0x1b, 0x68, 0x9b, 0x00, 0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, -0x0a, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, -0x70, 0x47, 0x08, 0x4b, 0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, -0x00, 0x20, 0xf6, 0xe7, 0x88, 0x03, 0x00, 0x80, 0xa8, 0x03, 0x00, 0x80, -0xa0, 0x03, 0x00, 0x80, 0x98, 0x03, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0x90, 0x03, 0x00, 0x80, 0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, -0x01, 0xb6, 0xa0, 0xe3, 0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, -0x01, 0x7a, 0xa0, 0xe3, 0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, -0xc8, 0x60, 0x9f, 0xe5, 0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, -0x00, 0x00, 0x54, 0xe3, 0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, -0x11, 0x00, 0x00, 0x0a, 0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, -0x21, 0x00, 0x00, 0x0a, 0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, -0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, -0x1c, 0x00, 0x85, 0xe5, 0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, -0x02, 0x0a, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, -0x02, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, -0x14, 0x80, 0x85, 0xe5, 0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, -0x1c, 0x00, 0x96, 0xe5, 0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, -0x1c, 0x00, 0x85, 0xe5, 0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, -0x40, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, -0x02, 0x0b, 0x14, 0xe3, 0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, -0x20, 0x00, 0x00, 0x1b, 0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, -0x18, 0x00, 0x89, 0xe5, 0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, +0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28, +0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48, +0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c, +0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80, +0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a, +0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03, +0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48, +0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23, +0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21, +0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9, +0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42, +0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55, +0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80, +0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a, +0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60, +0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b, +0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b, +0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00, +0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68, +0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b, +0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7, +0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80, +0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80, +0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3, +0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3, +0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5, +0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3, +0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a, +0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a, +0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, +0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3, +0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3, +0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5, +0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, +0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, +0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b, +0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3, +0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b, +0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5, +0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3, +0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8, -0x04, 0xf0, 0x5e, 0xe2, 0xe8, 0x0d, 0x00, 0x80, -0x08, 0x83, 0x20, 0x40, 0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, -0x00, 0x20, 0xc3, 0xe1, 0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, -0x0c, 0x20, 0x81, 0xe5, 0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, -0x18, 0x10, 0x9f, 0xe5, 0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, -0xb0, 0x24, 0xc1, 0xe1, 0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, -0x3c, 0x00, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, -0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, -0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, -0x24, 0x20, 0x91, 0xe5, 0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x24, 0x20, 0x80, 0xe5, 0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x28, 0x10, 0x80, 0xe5, 0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, -0x2c, 0x20, 0x80, 0xe5, 0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, -0x1e, 0xff, 0x2f, 0x11, 0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, -0x01, 0x10, 0x81, 0xe2, 0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, -0x0b, 0x02, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, -0xb0, 0x03, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, -0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, +0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, +0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1, +0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5, +0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5, +0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1, +0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5, +0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea, +0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3, +0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5, +0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5, +0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5, +0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5, +0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11, +0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2, +0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3, +0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80, +0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, +0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2, +0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1, +0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3, +0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5, +0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00, +0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, +0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, +0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, -0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, +0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, -0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, -0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, -0x0c, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, -0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, -0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, -0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, -0x4c, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, -0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, -0x01, 0x06, 0xa0, 0xe3, 0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, -0x80, 0x21, 0x1f, 0xe5, 0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x00, 0x30, 0x80, 0xe5, 0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x81, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, -0x01, 0x06, 0xa0, 0xe3, 0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, -0x1c, 0x10, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, -0x1e, 0xff, 0x2f, 0xe1, 0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x1c, 0x10, 0x82, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, -0x0c, 0x00, 0x81, 0xe5, 0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, -0x1c, 0x00, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, -0x38, 0x1c, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c, -0x00, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, -0x09, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x68, 0xf8, -0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, -0x3a, 0x78, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, -0xff, 0x22, 0x01, 0x32, 0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, -0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, -0x5b, 0x02, 0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, -0x82, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, -0x1a, 0x43, 0x08, 0x2a, 0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, -0x41, 0x60, 0x81, 0x68, 0x0e, 0x31, 0x2c, 0xe0, 0x13, 0x02, 0x12, 0x0a, -0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x2e, 0x3a, -0x16, 0x4b, 0x9a, 0x42, 0x24, 0xd8, 0x01, 0x25, 0x42, 0x68, 0x15, 0x43, -0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x12, 0x4b, -0x9a, 0x42, 0x19, 0xd1, 0xfb, 0x1d, 0x09, 0x33, 0x44, 0xcb, 0x9b, 0x07, -0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33, 0x9e, 0x40, 0x16, 0x43, -0x03, 0x2e, 0x0f, 0xd1, 0x39, 0x7d, 0x7b, 0x7d, 0x1b, 0x02, 0x19, 0x43, -0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43, 0x41, 0x60, 0x81, 0x68, -0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x01, 0xe0, 0x00, 0x21, 0x84, 0x60, -0x08, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xae, 0x05, 0x00, 0x00, -0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68, 0xd1, 0x08, 0x3f, 0xd3, -0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39, 0x8f, 0x78, 0x3f, 0x07, -0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d, 0x0d, 0x32, 0xc2, 0x60, -0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60, 0x08, 0x23, 0x1a, 0x43, -0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f, 0x92, 0x00, 0x02, 0x61, -0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, -0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x61, -0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23, 0x42, 0x68, 0x1a, 0x43, -0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23, 0x42, 0x68, 0x1a, 0x43, -0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23, 0x42, 0x68, 0x1a, 0x43, -0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23, 0x42, 0x68, 0x1a, 0x43, -0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76, 0x80, 0xbc, 0x70, 0x47, -0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78, 0x1b, 0x02, 0x1a, 0x43, -0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43, 0x02, 0x60, 0xc9, 0x78, -0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x07, 0x1c, -0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a, 0xc9, 0x68, 0x40, 0x18, -0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, -0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42, 0x18, 0xd1, 0x78, 0x6a, -0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xb0, 0xf8, -0x38, 0x1c, 0x01, 0xf0, 0x6d, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, -0xc8, 0x72, 0x07, 0x49, 0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, -0x8a, 0x6d, 0x12, 0x18, 0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x20, 0xfa, 0xe7, 0x98, 0x19, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, -0x10, 0x2a, 0x00, 0x80, 0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, -0x01, 0x23, 0x9b, 0x07, 0x01, 0x1d, 0x18, 0x43, -0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02, 0x12, 0x0e, 0x12, 0x06, -0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40, 0x10, 0x43, 0x0a, 0x0a, -0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02, 0x1b, 0x0a, 0x19, 0x40, -0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, -0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04, 0x1a, 0x40, 0x11, 0x43, -0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43, 0x00, 0x0e, 0x08, 0x43, -0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23, 0x81, 0x6b, 0x19, 0x40, -0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d, 0x39, 0x37, 0x39, 0x7b, -0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1, 0x01, 0x6b, 0xc0, 0x46, -0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d, 0x2d, 0x35, 0x00, 0x22, -0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50, 0x01, 0x32, 0x07, 0x2a, -0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63, 0x82, 0x6a, 0xc0, 0x46, -0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33, 0x5a, 0x83, 0x40, 0x6a, -0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27, 0x42, 0x68, 0x00, 0x2a, -0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1, 0x42, 0x69, 0x00, 0x2a, -0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a, 0x02, 0x29, 0x02, 0xd3, -0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0, 0x13, 0xf8, 0x09, 0xe0, -0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x03, 0xe0, -0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61, 0x38, 0x1c, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0xec, 0x05, 0x00, 0x80, -0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b, 0x34, 0xd0, -0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68, 0x9b, 0x6a, 0xc0, 0x46, -0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19, 0x7f, 0x02, 0x17, 0x4b, -0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63, 0x07, 0x63, 0xcb, 0x1d, -0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69, 0x00, 0x2b, 0x01, 0xd0, -0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61, 0x0f, 0x1c, 0xc9, 0x68, -0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63, 0xf8, 0x1d, 0xff, 0x30, -0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60, 0xc2, 0x60, 0x38, 0x1c, -0x00, 0xf0, 0xc4, 0xfa, 0x38, 0x6a, 0x01, 0x30, 0x38, 0x62, 0x38, 0x1c, -0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, -0xfa, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, -0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31, 0x88, 0x6a, 0xc2, 0x1d, -0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32, 0x1a, 0x43, 0xc8, 0x6a, -0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18, 0x82, 0x79, 0xc3, 0x79, -0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, -0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38, 0x92, 0x04, 0x92, 0x0c, -0x00, 0x26, 0x25, 0x4d, 0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, -0x04, 0xd0, 0x20, 0x8a, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, -0x01, 0x23, 0x9b, 0x07, 0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, -0x12, 0x04, 0x12, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, -0x10, 0x43, 0x03, 0x1c, 0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, -0xc8, 0x6b, 0x19, 0x1c, 0x01, 0xf0, 0xd8, 0xff, 0x00, 0x28, 0x04, 0xda, -0x20, 0x8a, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, -0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x08, 0x60, 0x01, 0x04, -0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8, 0x00, 0x28, 0x14, 0xd1, -0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43, 0x20, 0x82, 0x21, 0x8a, -0x38, 0x1c, 0x00, 0xf0, 0x98, 0xfb, 0xe8, 0x68, 0x01, 0x23, 0x9b, 0x07, -0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xe8, 0x60, 0x30, 0x1c, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00, -0xec, 0x05, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0xfc, 0x1d, 0xf9, 0x34, -0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35, 0x33, 0x48, 0xc0, 0x6a, -0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18, 0x01, 0x20, 0x80, 0x07, -0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x90, 0x01, 0x23, -0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43, 0x00, 0x68, 0x38, 0x1c, -0x29, 0x1c, 0x00, 0xf0, 0xb8, 0xfa, 0xa8, 0x88, 0x40, 0x07, 0x01, 0xd0, -0x00, 0x20, 0x47, 0xe0, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a, +0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3, +0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5, +0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5, +0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5, +0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3, +0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5, +0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, +0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5, +0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5, +0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5, +0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, +0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c, +0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28, +0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07, +0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32, +0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, +0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68, +0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0, +0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a, +0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, +0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1, +0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42, +0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0, +0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, +0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25, +0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02, +0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33, +0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33, +0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d, +0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43, +0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0, +0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03, +0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c, +0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00, +0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68, +0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39, +0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d, +0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60, +0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f, +0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43, +0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, +0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23, +0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23, +0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23, +0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23, +0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76, +0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78, +0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43, +0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47, +0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a, +0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43, +0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42, +0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, +0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xd0, 0xf8, 0x38, 0x1c, 0x01, 0xf0, +0x8b, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49, +0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18, +0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7, +0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, +0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07, +0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02, +0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40, +0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02, +0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07, +0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04, +0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43, +0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23, +0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d, +0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1, +0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d, +0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50, +0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63, +0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33, +0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27, +0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1, +0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a, +0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0, +0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61, +0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61, +0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, +0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68, +0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68, +0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19, +0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63, +0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69, +0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61, +0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63, +0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60, +0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30, +0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, +0x1c, 0xad, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31, +0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32, +0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18, +0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, +0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38, +0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d, +0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a, +0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07, +0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30, +0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c, +0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c, +0x01, 0xf0, 0xf8, 0xff, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23, +0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, +0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8, +0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43, +0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68, +0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, +0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, +0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, +0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35, +0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18, +0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, +0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43, +0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88, +0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18, +0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18, +0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a, 0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0, -0x2b, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69, +0x29, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58, 0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28, 0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28, -0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xd4, 0xfb, +0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b, -0xff, 0xf7, 0xcc, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, -0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0xc4, 0xfb, 0xa1, 0x6b, 0x08, 0x4a, -0x01, 0x20, 0xff, 0xf7, 0xbf, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46, +0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, +0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a, +0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46, 0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0xc8, 0x29, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00, -0xec, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a, +0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00, +0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a, 0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48, 0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00, @@ -409,18 +418,18 @@ 0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a, 0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b, -0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69, 0x09, 0x04, 0x09, 0x0c, -0x01, 0xf0, 0x1e, 0xf9, 0x28, 0x6b, 0x79, 0x69, 0x40, 0x18, 0xc1, 0x1d, -0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b, 0xd3, 0x18, 0xff, 0x33, -0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50, 0x01, 0x30, 0x04, 0x28, -0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00, 0x56, 0x18, 0x01, 0x23, -0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae, 0xb3, 0x50, 0x01, 0x30, -0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90, 0x90, 0x49, 0x42, 0x00, -0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0, 0x8e, 0x48, 0xc1, 0x89, -0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28, +0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69, +0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x1c, 0xf9, 0x28, 0x6b, 0x79, 0x69, +0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b, +0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50, +0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00, +0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae, +0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90, +0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0, +0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a, 0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0, -0x47, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98, +0x5d, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98, 0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60, @@ -452,20 +461,20 @@ 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04, 0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1, -0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d, 0x05, 0x31, 0x19, 0x43, -0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60, 0xe8, 0x6a, 0xc0, 0x46, -0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x92, 0xfc, 0x20, 0x7e, 0x33, 0x28, -0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21, 0x14, 0x4c, 0xc0, 0x46, -0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x85, 0xf8, 0x28, 0x6b, -0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c, 0xff, 0xf7, 0xca, 0xfd, -0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20, 0x30, 0x72, 0x11, 0xe0, -0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1, 0x07, 0x1c, 0x00, 0xf0, -0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xba, 0xfd, -0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x50, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc, +0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d, +0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60, +0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc, +0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21, +0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0, +0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c, +0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20, +0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1, +0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd, +0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x66, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00, -0xec, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x29, 0x00, 0x80, -0x1c, 0xad, 0x20, 0x40, 0xc0, 0x06, 0x00, 0x80, 0x02, 0x07, 0x00, 0x80, -0x78, 0x2a, 0x00, 0x80, 0xec, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48, +0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80, +0x1c, 0xad, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80, +0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48, 0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31, 0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46, @@ -476,10 +485,10 @@ 0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46, 0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46, 0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a, -0x01, 0xf0, 0x14, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, +0x01, 0xf0, 0x28, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, -0x2c, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a, +0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, +0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68, 0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31, 0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0, @@ -495,15 +504,15 @@ 0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d, 0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32, -0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d, 0xff, 0x37, 0x4a, 0x37, -0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d, 0xff, 0x34, 0x3a, 0x34, -0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30, 0xe8, 0x60, 0x60, 0x69, -0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07, 0x38, 0x1d, 0x18, 0x43, -0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, -0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63, 0xf8, 0x1d, 0x03, 0x30, -0xff, 0xf7, 0x06, 0xfc, 0x20, 0x62, 0xf8, 0x1d, 0x07, 0x30, 0xff, 0xf7, -0x01, 0xfc, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76, 0xb0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98, +0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d, +0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d, +0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30, +0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07, +0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43, +0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63, +0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d, +0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76, +0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98, 0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40, 0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c, @@ -537,86 +546,85 @@ 0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61, 0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b, 0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83, -0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xa4, 0xf8, -0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xb0, 0xb5, 0x1b, 0x4c, -0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20, 0xe7, 0x1d, 0x19, 0x37, -0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30, 0x00, 0x29, 0x15, 0xd0, -0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25, 0x0a, 0xe0, 0xff, 0xf7, -0x93, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a, 0x02, 0x28, 0x00, 0xd3, -0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28, -0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x6a, 0x00, 0x28, -0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69, 0x00, 0x28, 0x04, 0xd0, -0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0x8e, 0xfc, +0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xb8, 0xf8, +0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, +0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20, +0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30, +0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25, +0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a, +0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0, +0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69, +0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0x9e, 0xfc, 0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x50, 0xf8, -0xe9, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xb4, 0x03, 0x00, 0x80, +0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x00, 0x25, 0x00, 0x28, 0x03, 0xd1, 0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x23, 0x48, 0x68, 0x18, 0x40, 0x01, 0x24, 0x00, 0x28, 0x03, 0xd1, -0x38, 0x6a, 0x00, 0xf0, 0x0d, 0xfc, 0x2f, 0xe0, 0x38, 0x1c, 0x00, 0xf0, -0x1d, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7e, 0xfa, 0xb8, 0x68, 0xc0, 0x08, -0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd2, 0xfb, 0xb8, 0x68, 0x39, 0x6a, +0x38, 0x6a, 0x00, 0xf0, 0x09, 0xfc, 0x2f, 0xe0, 0x38, 0x1c, 0x00, 0xf0, +0x19, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x78, 0xfa, 0xb8, 0x68, 0xc0, 0x08, +0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xce, 0xfb, 0xb8, 0x68, 0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60, 0x0f, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x11, 0xf8, 0x0b, 0xe0, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c, 0xc0, 0xe7, -0xec, 0x05, 0x00, 0x80, 0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, +0x6c, 0x06, 0x00, 0x80, 0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, -0xc7, 0xfb, 0x00, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, -0xfa, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, +0xc3, 0xfb, 0x00, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, +0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36, 0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, -0x2d, 0x4b, 0x9d, 0x42, 0x56, 0xd0, 0x2d, 0x4c, 0x38, 0x1c, 0x21, 0x1c, -0x2a, 0x1c, 0x00, 0xf0, 0x23, 0xf9, 0xa0, 0x88, 0x40, 0x07, 0x4d, 0xd1, -0x29, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18, 0x01, 0x23, -0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x25, 0x4d, -0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d, 0x19, 0x31, -0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d, 0x21, 0x32, -0x00, 0xf0, 0xe2, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, -0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x00, 0x22, -0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3, 0x21, 0x1c, -0x16, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x9a, 0xff, 0x01, 0x22, 0x52, 0x04, -0x78, 0x68, 0x02, 0x43, 0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x92, 0xff, -0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, -0xfe, 0xf7, 0x8a, 0xff, 0x0d, 0x49, 0x0e, 0x4a, 0x01, 0x20, 0xfe, 0xf7, -0x85, 0xff, 0x01, 0x20, 0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, -0xea, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x20, 0xfa, 0xe7, 0xff, 0xff, 0x00, 0x00, 0x98, 0xad, 0x20, 0x40, -0xc8, 0x29, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, -0x84, 0xad, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0, -0x00, 0x21, 0x58, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21, -0xc9, 0x04, 0x56, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31, -0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x53, 0x48, 0x00, 0x68, 0x03, 0xf0, -0x97, 0xfb, 0x98, 0xe0, 0x4e, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34, -0x22, 0x78, 0x50, 0x00, 0xc0, 0x19, 0x80, 0x8b, -0x4d, 0x49, 0x89, 0x6a, 0x58, 0x23, 0x58, 0x43, 0x0d, 0x18, 0x01, 0x23, -0x9b, 0x07, 0xe9, 0x1d, 0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x35, +0x33, 0x4c, 0x34, 0x4b, 0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, +0x2a, 0x1c, 0x00, 0xf0, 0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, +0x69, 0x43, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, +0x00, 0x04, 0x00, 0x0c, 0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, +0xc0, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, +0x09, 0x7b, 0xea, 0x1d, 0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, +0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, +0x05, 0x31, 0x00, 0x20, 0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, +0x06, 0x28, 0xfa, 0xd3, 0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, +0x09, 0x18, 0x78, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, +0x61, 0x89, 0xe2, 0x88, 0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, +0xfe, 0xf7, 0x64, 0xff, 0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43, +0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x5c, 0xff, 0x01, 0x22, 0x52, 0x04, +0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, +0xfe, 0xf7, 0x54, 0xff, 0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, +0x4f, 0xff, 0x01, 0x20, 0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, +0xea, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0xd9, 0xe7, 0x98, 0xad, 0x20, 0x40, +0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, +0x54, 0x00, 0x03, 0x00, 0x84, 0xad, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, +0xf0, 0xb5, 0x83, 0xb0, 0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, +0x51, 0x62, 0x01, 0x21, 0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, +0xc1, 0x1d, 0x19, 0x31, 0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, +0x00, 0x68, 0x03, 0xf0, 0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, +0xfc, 0x1d, 0x49, 0x34, 0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, +0x44, 0x4a, 0x92, 0x6a, 0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, +0x9b, 0x07, 0xea, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68, 0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, -0x45, 0x4d, 0x01, 0x2b, 0x24, 0xd1, 0xd0, 0x19, 0xc1, 0x1d, 0x19, 0x31, -0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x42, 0x4a, 0x09, 0x7b, 0x00, 0xf0, -0xd3, 0xfc, 0x20, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, +0x3c, 0x4d, 0x01, 0x2b, 0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, +0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, +0xc5, 0xfc, 0x20, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20, 0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20, 0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, -0x01, 0x30, 0x06, 0x28, 0xf8, 0xd3, 0x3e, 0xe0, 0x02, 0x2b, 0x3c, 0xd1, -0x09, 0x0a, 0x3a, 0xd3, 0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, +0x01, 0x30, 0x06, 0x28, 0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, +0x11, 0x0a, 0x29, 0xd3, 0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19, 0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00, 0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, -0x06, 0x29, 0xf8, 0xd3, 0x22, 0x49, 0x8a, 0x6a, 0x12, 0x18, 0x01, 0x23, -0x9b, 0x07, 0xd5, 0x1d, 0x49, 0x35, 0x2b, 0x43, 0x6e, 0x46, 0x1d, 0x68, -0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x6b, 0x40, 0x1e, 0x4d, -0xee, 0x68, 0x73, 0x40, 0x13, 0x65, 0x89, 0x6a, 0x08, 0x18, 0x01, 0x23, -0x9b, 0x07, 0xc1, 0x1d, 0x4d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x6a, 0x46, -0x08, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x51, 0x40, 0xaa, 0x69, 0x51, 0x40, -0x41, 0x65, 0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, -0x38, 0x1c, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x09, 0x4a, -0x50, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, -0xa3, 0xfa, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x72, 0xfa, 0x01, 0xf0, -0xc3, 0xfa, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0xec, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xb8, 0x03, 0x00, 0x80, -0xc8, 0x29, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 0x14, 0x06, 0x00, 0x80, +0x06, 0x29, 0xf8, 0xd3, 0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, +0x00, 0x9d, 0x55, 0x40, 0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, +0x89, 0x6a, 0x08, 0x18, 0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, +0x51, 0x40, 0x41, 0x65, 0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, +0x0d, 0xd0, 0x38, 0x1c, 0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, +0x08, 0x4a, 0x50, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, +0x00, 0xf0, 0xa4, 0xfa, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, +0x01, 0xf0, 0xde, 0xfa, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, +0x4c, 0x2a, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43, 0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, @@ -625,14 +633,14 @@ 0xff, 0x26, 0x36, 0x02, 0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c, 0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89, -0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18, -0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, -0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, -0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36, -0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18, -0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23, -0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c, -0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, +0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, +0x01, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, +0x33, 0x43, 0x1b, 0x68, 0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, +0x05, 0x2c, 0xf0, 0xd3, 0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, +0xde, 0x1d, 0x1d, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, +0x00, 0x9e, 0x76, 0x18, 0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, +0x06, 0xe0, 0x00, 0x23, 0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, +0x0c, 0x60, 0x23, 0x1c, 0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33, 0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b, 0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, @@ -653,29 +661,29 @@ 0x05, 0x28, 0xf2, 0xd3, 0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xc8, 0x29, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, +0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2, 0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46, 0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68, 0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69, 0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc, 0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60, 0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, -0x01, 0x61, 0xf2, 0xe7, 0xac, 0x06, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, +0x01, 0x61, 0xf2, 0xe7, 0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98, 0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27, 0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, -0x00, 0x2b, 0x19, 0xd0, 0xa2, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, +0x00, 0x2b, 0x19, 0xd0, 0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0, 0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23, 0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b, -0x18, 0xd0, 0x94, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, -0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, -0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0, -0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0, -0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89, -0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68, -0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c, -0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, +0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, +0x58, 0x23, 0x63, 0x43, 0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, +0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, +0x0f, 0x43, 0x07, 0xe0, 0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, +0x1f, 0x43, 0x01, 0xe0, 0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, +0x07, 0x91, 0x4b, 0x89, 0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, +0x08, 0x9d, 0x2d, 0x68, 0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, +0x1a, 0xd3, 0x1a, 0x1c, 0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46, 0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87, 0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b, 0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, @@ -684,7 +692,7 @@ 0x07, 0x9b, 0x9b, 0x89, 0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00, 0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a, 0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, -0xc0, 0x46, 0xab, 0x83, 0x31, 0x71, 0x64, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, +0xc0, 0x46, 0xab, 0x83, 0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31, 0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, @@ -692,7 +700,7 @@ 0x24, 0x0c, 0x05, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33, 0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, -0xbb, 0x08, 0x9b, 0x07, 0x6b, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, +0xbb, 0x08, 0x9b, 0x07, 0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b, 0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, @@ -701,102 +709,103 @@ 0x2b, 0x43, 0x55, 0x00, 0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b, 0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e, 0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, -0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40, -0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c, -0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78, -0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3, -0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00, -0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33, -0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93, -0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, -0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, -0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0, 0x10, 0x31, 0x81, 0x23, -0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, -0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, -0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 0x03, 0x9c, 0x40, 0x34, -0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46, 0xd9, 0x80, 0x51, 0x1e, -0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61, 0x04, 0x2a, 0x06, 0xd2, -0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83, 0x01, 0x32, 0x04, 0x2a, -0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0xc8, 0x29, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, -0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68, -0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68, -0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48, -0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0, -0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98, -0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xcd, 0xff, 0x68, 0x46, -0x02, 0xf0, 0x82, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x78, 0x2a, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0, -0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, -0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x6c, 0xfe, -0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, -0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46, -0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68, -0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68, -0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69, -0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28, -0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7, -0xec, 0x05, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60, -0x08, 0x60, 0x70, 0x47, 0xec, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22, -0x12, 0x4f, 0x3b, 0x7f, 0x01, 0x33, 0x3b, 0x77, 0x03, 0x23, 0xfc, 0x1d, -0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68, -0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68, -0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62, -0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60, -0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64, -0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, -0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00, -0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23, -0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0xe0, 0x6a, 0x01, 0x30, -0xe0, 0x62, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69, -0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, -0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, -0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, -0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x3a, 0xfe, 0x38, 0x68, 0x01, 0x28, -0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, -0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, -0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, -0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, -0x1f, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1, 0xbb, 0x23, 0x1b, 0x01, -0xee, 0x18, 0x70, 0x7a, 0x00, 0x28, 0x03, 0xd0, 0x00, 0x20, 0x70, 0x72, -0x00, 0xf0, 0x30, 0xfd, 0x30, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x78, 0x68, -0x02, 0xf0, 0x96, 0xff, 0x1b, 0x23, 0xdb, 0x01, 0xe8, 0x18, 0x40, 0x8b, -0x04, 0x26, 0x06, 0x40, 0xa0, 0x6a, 0xb0, 0x42, -0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3, -0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30, -0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x7c, 0xff, -0x00, 0x20, 0xf8, 0x60, 0xa6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60, -0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xa0, 0x6b, -0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0xef, 0xfb, 0x02, 0x23, -0xa0, 0x6b, 0x98, 0x43, 0xa0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60, -0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xbc, 0x03, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xd0, 0x2c, 0x00, 0x80, -0x50, 0x2c, 0x00, 0x80, 0xa8, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x1c, 0x48, -0x02, 0x8a, 0x1c, 0x49, 0x0f, 0x8a, 0x01, 0x23, 0xba, 0x42, 0x03, 0xd1, -0xc2, 0x89, 0x4f, 0x8a, 0xba, 0x42, 0x10, 0xd0, 0x02, 0x7b, 0x00, 0x2a, -0x0d, 0xd0, 0x42, 0x7b, 0x00, 0x2a, 0x0a, 0xd0, 0xc7, 0x8a, 0x8a, 0x8a, -0x97, 0x42, 0x04, 0xdc, 0x13, 0x4a, 0xc0, 0x46, 0x53, 0x60, 0x8b, 0x82, -0x01, 0xe0, 0x01, 0x32, 0x8a, 0x82, 0x42, 0x8b, 0x57, 0x1c, 0x47, 0x83, -0x07, 0x8b, 0xba, 0x42, 0x0e, 0xdb, 0x07, 0x8a, 0x84, 0x8a, 0x00, 0x22, -0xa7, 0x42, 0x05, 0xda, 0xc7, 0x89, 0x44, 0x8a, 0xa7, 0x42, 0x01, 0xda, -0x42, 0x73, 0x00, 0xe0, 0x43, 0x73, 0xc2, 0x81, 0x02, 0x82, 0x42, 0x83, -0xc2, 0x89, 0xc0, 0x46, 0x4a, 0x82, 0x00, 0x8a, 0xc0, 0x46, 0x08, 0x82, -0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xbc, 0x03, 0x00, 0x80, -0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0, 0x6b, 0x46, 0x84, 0x1e, -0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20, 0x81, 0x00, 0x67, 0x58, -0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, -0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00, 0xd6, 0x59, 0x4f, 0x1c, -0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00, 0xde, 0x51, 0x29, 0x1c, -0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 0xf1, 0xd3, 0x09, 0xe0, -0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46, 0x53, 0x50, 0x01, 0x30, -0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3, 0x00, 0x20, 0xe0, 0x70, -0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73, 0x60, 0x73, 0x12, 0x99, -0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c, 0x91, 0x78, 0x09, 0x07, -0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06, 0x2d, 0x16, 0x00, 0x27, -0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9, 0x00, 0xf0, 0x3d, 0xf8, -0x00, 0x28, 0x0e, 0xd0, 0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, -0x09, 0xdd, 0x00, 0x22, 0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, +0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, +0x04, 0x25, 0x3d, 0x40, 0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, +0xb3, 0x83, 0x13, 0x1c, 0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, +0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, +0x3b, 0x09, 0x37, 0xd3, 0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, +0x03, 0x8b, 0x55, 0x00, 0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, +0x03, 0x93, 0x20, 0x33, 0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, +0x1b, 0x18, 0x02, 0x93, 0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, +0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, +0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0, +0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, +0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, +0x02, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, +0x10, 0x3b, 0x9b, 0x7b, 0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, +0x07, 0x9b, 0xc0, 0x46, 0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, +0x19, 0x70, 0x07, 0x61, 0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, +0x1b, 0x18, 0x99, 0x83, 0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, +0xff, 0xff, 0x00, 0x00, 0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, +0x12, 0x48, 0x01, 0x68, 0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, +0x00, 0x90, 0x78, 0x68, 0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, +0x02, 0x90, 0x0d, 0x48, 0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, +0x38, 0x1c, 0x00, 0xf0, 0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, +0x10, 0x23, 0x02, 0x98, 0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, +0xe1, 0xff, 0x68, 0x46, 0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, +0x00, 0xb5, 0x8c, 0xb0, 0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, +0x05, 0x4b, 0x19, 0x43, 0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, +0x02, 0xf0, 0x84, 0xfe, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0xa0, 0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, +0x40, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, +0x90, 0x80, 0xc8, 0x68, 0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, +0x10, 0x81, 0x88, 0x68, 0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, +0x90, 0x73, 0x08, 0x69, 0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, +0x08, 0x68, 0x00, 0x28, 0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, +0x0a, 0x60, 0xfa, 0xe7, 0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, +0xc0, 0x46, 0xc2, 0x60, 0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, +0xb0, 0xb4, 0x00, 0x22, 0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, +0x03, 0x23, 0xfc, 0x1d, 0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, +0x0e, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, +0x10, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, +0xc0, 0x46, 0xfb, 0x62, 0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, +0x99, 0x60, 0x58, 0x60, 0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, +0x10, 0x1c, 0x38, 0x64, 0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, +0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, +0x40, 0x01, 0x18, 0x00, 0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, +0x47, 0x4d, 0x07, 0x23, 0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, +0x20, 0x6b, 0x01, 0x30, 0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, +0x43, 0x48, 0x41, 0x69, 0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, +0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, +0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, +0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe, +0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29, +0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, +0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, +0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, +0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, +0x02, 0x28, 0x2f, 0xd1, 0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, +0x00, 0x28, 0x03, 0xd0, 0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, +0x30, 0x7b, 0x00, 0x28, 0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, +0x1b, 0x23, 0xdb, 0x01, 0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, +0xe0, 0x6a, 0xb0, 0x42, 0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, +0x19, 0x28, 0x11, 0xd3, 0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, +0xff, 0x30, 0x41, 0x30, 0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, +0x02, 0xf0, 0x90, 0xff, 0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, +0x00, 0x20, 0xf8, 0x60, 0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, +0x79, 0x34, 0xe0, 0x6b, 0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, +0x07, 0xfc, 0x02, 0x23, 0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, +0x01, 0x30, 0x38, 0x60, 0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, +0xa0, 0x82, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, +0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, +0xb0, 0xb4, 0x1d, 0x48, 0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, +0x09, 0x31, 0x01, 0x27, 0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, +0xa3, 0x42, 0x10, 0xd0, 0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, +0x00, 0x2b, 0x0a, 0xd0, 0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, +0x13, 0x4b, 0xc0, 0x46, 0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, +0x93, 0x82, 0xc3, 0x8b, 0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, +0x0e, 0xdb, 0x84, 0x8a, 0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, +0x44, 0x8a, 0xc5, 0x8a, 0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, +0x4f, 0x70, 0x43, 0x82, 0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, +0x51, 0x82, 0x80, 0x8a, 0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, +0xe8, 0x0e, 0x00, 0x80, 0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, +0xf7, 0xb5, 0x91, 0xb0, 0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, +0x1a, 0xd9, 0x00, 0x20, 0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, +0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, +0x05, 0x20, 0x87, 0x00, 0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, +0x0f, 0x1c, 0xbf, 0x00, 0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, +0x00, 0x0e, 0x10, 0x28, 0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, +0x63, 0x58, 0xc0, 0x46, 0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, +0x06, 0x28, 0xf6, 0xd3, 0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, +0xa0, 0x72, 0x20, 0x73, 0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, +0x69, 0x46, 0x8e, 0x1c, 0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, +0x14, 0x39, 0x0d, 0x06, 0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, +0xf0, 0x19, 0x10, 0xa9, 0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0, +0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22, +0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9, 0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d, 0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, @@ -804,257 +813,261 @@ 0x09, 0x06, 0x09, 0x0e, 0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0, 0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, -0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x83, 0x42, -0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4, 0x02, 0x78, 0xd2, 0x06, -0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a, 0x01, 0xdc, 0x0f, 0x70, -0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70, 0x14, 0x2a, 0x04, 0xd1, -0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72, 0x07, 0xe0, 0x02, 0x2a, -0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a, 0x01, 0xd0, 0x15, 0x2a, -0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47, 0x38, 0x1c, 0xfb, 0xe7, -0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48, 0x01, 0x23, 0x1b, 0x06, -0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, -0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c, 0x09, 0x4a, 0xc0, 0x46, -0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x40, 0x69, 0x00, 0x28, -0x03, 0xd0, 0x02, 0xf0, 0x4f, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x04, 0x48, -0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40, 0x70, 0x47, 0x00, 0x00, -0xf0, 0xb5, 0x85, 0xb0, 0x94, 0x49, 0xc8, 0x68, 0xcf, 0x1d, 0x79, 0x37, -0x01, 0x28, 0x0b, 0xd1, 0xb8, 0x88, 0x00, 0x28, 0x08, 0xd1, 0xc3, 0x1e, -0xca, 0x6f, 0x1a, 0x40, 0xca, 0x67, 0x8f, 0x48, 0xc0, 0x46, 0x02, 0x60, -0x14, 0x20, 0xb8, 0x80, 0x8d, 0x4c, 0x62, 0x6a, 0x8d, 0x48, 0xc3, 0x6b, -0x9a, 0x18, 0xc2, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xcc, 0x18, -0x60, 0x62, 0xe2, 0x69, 0x12, 0x03, 0x12, 0x0b, 0x82, 0x42, 0x05, 0xd1, -0x01, 0x20, 0x40, 0x04, 0x86, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xef, 0xe0, -0x3b, 0x8a, 0x58, 0x1c, 0x38, 0x82, 0xbd, 0x8a, 0x01, 0x20, 0x00, 0x22, -0xab, 0x42, 0x02, 0xdb, 0x78, 0x73, 0x3a, 0x82, 0x7a, 0x83, 0x33, 0x23, -0x9b, 0x01, 0xcb, 0x18, 0x04, 0x93, 0x1b, 0x69, 0x0f, 0x2b, 0x73, 0xd2, -0x00, 0x22, 0x2f, 0x23, 0x9b, 0x01, 0xcf, 0x18, 0xfa, 0x60, 0xe1, 0x69, -0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c, 0x36, 0x04, -0x76, 0x4d, 0x05, 0xd1, 0x3b, 0x2a, 0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, -0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x72, 0xc7, 0xe0, 0x01, 0x23, 0x9b, 0x07, -0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, -0x09, 0x88, 0x01, 0x31, 0x09, 0x04, 0x09, 0x0c, 0xf9, 0x81, 0x49, 0x09, -0x05, 0x31, 0x09, 0x06, 0x09, 0x0e, 0x6a, 0x4a, 0xc0, 0x46, 0x02, 0x92, -0x06, 0x1c, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46, 0x01, 0x93, 0x83, 0x6a, -0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32, 0x80, 0x69, 0x00, 0x03, -0x00, 0x0b, 0x92, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, -0x90, 0x42, 0x01, 0xd1, 0x30, 0x1c, 0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, -0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b, 0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, -0x12, 0x1a, 0x01, 0x20, 0x09, 0x01, 0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, -0x01, 0x28, 0x62, 0xd1, 0xe0, 0x68, 0x00, 0x28, 0x60, 0xd0, 0x04, 0x99, -0x08, 0x69, 0x01, 0x30, 0x08, 0x61, 0x02, 0x20, 0xe1, 0x69, 0xc0, 0x46, -0x08, 0x60, 0x00, 0xf0, 0x8f, 0xfc, 0x38, 0x63, 0x4e, 0x49, 0xc0, 0x46, -0x79, 0x60, 0xe1, 0x69, 0x62, 0x6b, 0x8a, 0x18, 0x23, 0x6b, 0x9a, 0x42, -0x00, 0xd9, 0xe1, 0x6a, 0xc0, 0x46, 0x79, 0x62, 0x79, 0x6a, 0x0c, 0x31, -0xb9, 0x62, 0x00, 0x21, 0xb9, 0x61, 0x03, 0xa9, 0x49, 0x88, 0xc9, 0x09, -0x03, 0xd3, 0x00, 0xe0, 0x78, 0xe0, 0x31, 0x1c, -0x00, 0xe0, 0x00, 0x21, 0x39, 0x60, 0x39, 0x68, 0xc0, 0x46, 0x01, 0x60, -0xf8, 0x89, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0x30, 0x83, 0xf8, 0x89, -0xc0, 0x46, 0x70, 0x83, 0x08, 0xe0, 0x60, 0x20, 0x30, 0x83, 0xf9, 0x89, -0xb8, 0x6a, 0x42, 0x18, 0x23, 0x6b, 0x9a, 0x42, 0x03, 0xd8, 0x71, 0x83, -0x00, 0x21, 0xf9, 0x62, 0x05, 0xe0, 0xe1, 0x6a, 0xc0, 0x46, 0xf9, 0x62, -0x21, 0x6b, 0x08, 0x1a, 0x70, 0x83, 0x38, 0x6b, 0x41, 0x68, 0xc0, 0x46, -0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x01, 0x69, 0xc0, 0x46, -0x39, 0x61, 0x40, 0x69, 0xc0, 0x46, 0x78, 0x61, 0x38, 0x1c, 0x00, 0xf0, -0x23, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xe0, 0xfa, -0xf8, 0x89, 0x71, 0x8b, 0x88, 0x42, 0x04, 0xd1, 0xb9, 0x6a, 0x08, 0x18, -0x04, 0xe0, 0x38, 0xe0, 0x32, 0xe0, 0xfa, 0x6a, 0x10, 0x18, 0x40, 0x1a, -0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x21, 0x6b, -0x09, 0x1a, 0x62, 0x6b, 0x91, 0x42, 0x00, 0xd2, 0xe0, 0x6a, 0xc0, 0x46, -0xe0, 0x61, 0xe8, 0x7a, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x21, 0xe9, 0x72, -0x04, 0x99, 0x08, 0x69, 0x01, 0x38, 0x08, 0x61, 0x38, 0x6b, 0x00, 0xf0, -0x5d, 0xfa, 0x18, 0x48, 0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, -0x0a, 0xd1, 0xe0, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x0c, 0x4c, 0xa1, 0x6a, -0x88, 0x42, 0x03, 0xd0, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x01, 0x20, 0x40, 0x04, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x05, 0xe0, -0xa0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x9f, 0xfa, 0xae, 0x72, -0xee, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, -0x00, 0x40, 0x14, 0x40, 0x10, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, -0x98, 0x19, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x28, 0x03, 0x00, 0x80, -0xe8, 0x19, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, +0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, +0x70, 0x47, 0x80, 0xb4, 0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, +0x01, 0x27, 0x01, 0x2a, 0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, +0xc0, 0x46, 0x08, 0x70, 0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, +0x01, 0x31, 0x01, 0x72, 0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, +0x03, 0xd0, 0x06, 0x2a, 0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, +0x80, 0xbc, 0x70, 0x47, 0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, +0x00, 0xb5, 0x0f, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, +0x1a, 0x09, 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, +0x91, 0x61, 0x19, 0x1c, 0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, +0xdb, 0x01, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, +0x61, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, +0x41, 0x80, 0xf8, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, +0xe0, 0x82, 0x20, 0x40, 0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, +0x95, 0x4a, 0xd0, 0x68, 0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, +0x38, 0x89, 0x00, 0x28, 0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, +0x99, 0x43, 0x01, 0x60, 0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, +0x8e, 0x48, 0xc3, 0x6b, 0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, +0xdb, 0x01, 0xd4, 0x18, 0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, +0x81, 0x42, 0x05, 0xd1, 0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, +0x08, 0x60, 0xf3, 0xe0, 0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, +0x01, 0x20, 0x00, 0x21, 0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, +0x58, 0x70, 0xb9, 0x82, 0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, +0x05, 0x93, 0x5b, 0x69, 0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, +0xc0, 0x46, 0x39, 0x61, 0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, +0x4b, 0x68, 0x1e, 0x0c, 0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, +0x05, 0xd1, 0x3b, 0x2a, 0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, +0x01, 0xd9, 0xa8, 0x73, 0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, +0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, +0x01, 0x31, 0x09, 0x04, 0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, +0x09, 0x06, 0x09, 0x0e, 0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, +0x43, 0x6a, 0xc0, 0x46, 0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, +0xc2, 0x1d, 0x11, 0x32, 0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, +0xb3, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20, +0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b, +0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, +0x01, 0x20, 0x09, 0x01, 0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, +0x65, 0xd1, 0x51, 0x49, 0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, +0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, +0x08, 0x60, 0x00, 0xf0, 0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, +0x22, 0x6a, 0xa3, 0x6b, 0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, +0x22, 0x6b, 0xc0, 0x46, 0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, +0x00, 0x22, 0xfa, 0x61, 0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, +0x01, 0x22, 0x00, 0xe0, 0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, +0x7a, 0x68, 0xc0, 0x46, 0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, +0x04, 0xdc, 0xb0, 0x83, 0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, +0x60, 0x20, 0xb0, 0x83, 0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, +0x9a, 0x42, 0x03, 0xd8, 0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, +0x21, 0x6b, 0xc0, 0x46, 0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, +0x2d, 0x49, 0x78, 0x6b, 0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, +0xc0, 0x46, 0xfa, 0x60, 0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, +0xc0, 0x46, 0xb8, 0x61, 0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, +0x37, 0xf9, 0x04, 0x98, 0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, +0x78, 0x8a, 0xf1, 0x8b, 0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, +0x04, 0xe0, 0x38, 0xe0, 0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, +0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, +0x09, 0x1a, 0xa2, 0x6b, 0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, +0x20, 0x62, 0xe8, 0x7b, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, +0x05, 0x99, 0x48, 0x69, 0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, +0x73, 0xfa, 0x18, 0x48, 0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, +0x0a, 0xd1, 0x20, 0x6a, 0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, +0x88, 0x42, 0x03, 0xd0, 0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x01, 0x20, 0x40, 0x04, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, +0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, +0xa8, 0x73, 0xed, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, +0xa4, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, +0x55, 0x55, 0x55, 0x55, 0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, +0xc4, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89, 0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c, 0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2, 0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31, 0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, -0x48, 0x62, 0x38, 0x6b, 0x00, 0xf0, 0xe2, 0xfb, 0x38, 0x1c, 0x00, 0xf0, -0x9f, 0xf8, 0x01, 0x20, 0x04, 0x49, 0xc0, 0x46, 0xc8, 0x72, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x10, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0x98, 0x19, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, +0x48, 0x62, 0x38, 0x6b, 0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, +0xb3, 0xf8, 0x01, 0x20, 0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, +0x18, 0x1a, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c, 0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89, 0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7, -0xc1, 0xff, 0x54, 0xe0, 0x2b, 0x48, 0x80, 0x6b, 0x00, 0x09, 0x1f, 0xd3, -0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a, -0x27, 0x4e, 0x9e, 0x19, 0x65, 0x23, 0x5b, 0x01, 0xf3, 0x18, 0x9b, 0x8b, -0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, -0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0, -0x13, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x60, 0xf8, 0x33, 0xe0, 0x01, 0x30, -0x03, 0x28, 0xe3, 0xd3, 0x1a, 0x48, 0x0b, 0x23, 0x1b, 0x02, 0xc1, 0x18, -0x09, 0x69, 0x00, 0x29, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x99, 0x49, 0x89, -0x09, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, -0x9b, 0x01, 0xc1, 0x18, 0x89, 0x6b, 0x00, 0x29, 0x18, 0xd0, 0x05, 0x1c, -0xfe, 0x1d, 0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, -0xd2, 0x18, 0x92, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7e, 0xfc, -0x01, 0x28, 0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, -0x9b, 0x01, 0xc0, 0x18, 0x80, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, -0x01, 0x2a, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0xf8, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x68, 0x1a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, -0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, -0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89, -0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08, -0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x10, 0xfc, 0x38, 0x1c, 0x00, 0xf0, -0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c, -0xff, 0xf7, 0x44, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47, -0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04, -0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29, -0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, -0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, -0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0, -0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68, -0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91, -0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab, -0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43, -0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69, -0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b, -0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a, -0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26, -0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0, -0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0, -0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42, 0x00, 0xd3, 0x00, 0x22, -0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43, 0x09, 0x68, 0xc0, 0x46, -0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, -0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, -0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a, 0xc0, 0x46, 0x51, 0x83, -0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x38, 0x63, -0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, -0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, -0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, -0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x81, -0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x60, 0xfb, -0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x58, 0xff, -0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x03, 0x00, 0x80, -0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c, -0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x38, 0x4a, 0x91, 0x42, 0x00, 0xdd, -0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d, -0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x12, 0xff, 0x32, 0x4a, 0xc0, 0x46, -0x00, 0x92, 0x32, 0x4e, 0x30, 0x6a, 0x32, 0x4c, 0xe1, 0x6d, 0x41, 0x18, -0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0, -0xff, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0xb1, 0x6a, 0x81, 0x42, 0x00, 0xd8, -0x00, 0x20, 0xe0, 0x65, 0x17, 0x23, 0xdb, 0x01, 0x20, 0x1c, 0xe1, 0x6d, -0xe4, 0x18, 0xe2, 0x6b, 0x92, 0x00, 0x27, 0x4b, 0xc0, 0x46, 0x99, 0x50, -0x26, 0x4d, 0xa8, 0x6b, 0x41, 0x08, 0x05, 0xd3, 0x40, 0x08, 0x40, 0x00, -0xa8, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd8, 0xff, 0x22, 0x4a, 0x1f, 0x48, -0x29, 0x7b, 0x00, 0x29, 0x02, 0xd0, 0x69, 0x7b, 0x00, 0x29, 0x00, 0xd1, -0x1f, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x05, 0x1c, 0xe0, 0x6b, 0x80, 0x00, -0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce, 0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, -0x02, 0xf0, 0xce, 0xfe, 0xe0, 0x6b, 0x01, 0x30, 0xe0, 0x63, 0x17, 0x28, -0x01, 0xd3, 0x00, 0x20, 0xe0, 0x63, 0x00, 0x20, 0x39, 0x6b, 0xc0, 0x46, -0x08, 0x65, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x33, 0x23, -0x9b, 0x01, 0xe8, 0x18, 0x41, 0x68, 0x00, 0x29, 0x03, 0xd1, 0x39, 0x6b, -0xc0, 0x46, 0x41, 0x60, 0x04, 0xe0, 0x39, 0x6b, 0x82, 0x68, 0xc0, 0x46, -0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0xf8, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0x18, 0x00, 0x14, 0x02, -0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0x44, 0x82, 0x20, 0x40, -0x68, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x03, -0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35, 0x10, 0x4f, 0xc0, 0x46, -0x35, 0x60, 0x38, 0x69, 0x01, 0x38, 0x38, 0x61, 0x7c, 0x68, 0x00, 0x2c, -0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0x78, 0x60, 0x20, 0x1c, 0x00, 0xf0, -0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa, 0x08, 0x48, 0x80, 0x6a, -0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71, 0xf7, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x00, 0xb0, 0xa8, 0x1a, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, -0xa0, 0x82, 0x20, 0x40, 0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, -0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, +0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, +0x00, 0x09, 0x1f, 0xd3, 0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, +0x43, 0x00, 0xcc, 0x5a, 0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, +0xf3, 0x18, 0x1b, 0x88, 0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, +0xc0, 0x46, 0x88, 0x61, 0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, +0x38, 0x1c, 0x00, 0xf0, 0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, +0x46, 0xe0, 0x01, 0x30, 0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, +0x5c, 0x18, 0xe4, 0x88, 0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, +0xf3, 0x18, 0x1b, 0x88, 0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, +0xd8, 0x42, 0xf0, 0xdc, 0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, +0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, +0x7d, 0x63, 0x00, 0x98, 0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, +0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, +0x17, 0xd0, 0xfe, 0x1d, 0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, +0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, +0x7b, 0xfc, 0x01, 0x28, 0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, +0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, +0x01, 0xe0, 0x01, 0x2a, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, +0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, +0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, +0xc0, 0x46, 0x88, 0x61, 0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, +0x78, 0x6a, 0x40, 0x89, 0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, +0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, +0x38, 0x1c, 0x00, 0xf0, 0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, +0x02, 0xe0, 0x38, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, +0x01, 0x60, 0x70, 0x47, 0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, +0x89, 0x08, 0x09, 0x04, 0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, +0x00, 0x20, 0x00, 0x29, 0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, +0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, +0x00, 0x04, 0x00, 0x0c, 0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, +0xf0, 0xb5, 0xa0, 0xb0, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, +0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, +0x19, 0x43, 0x1f, 0x91, 0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, +0x1e, 0x92, 0x17, 0xab, 0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, +0x0a, 0x6a, 0x13, 0x43, 0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, +0x09, 0x0b, 0x22, 0x69, 0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, +0x39, 0x34, 0x64, 0x8b, 0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, +0x1c, 0x94, 0x56, 0x1a, 0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, +0x00, 0x92, 0x01, 0x26, 0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, +0x32, 0x1c, 0x0b, 0xe0, 0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, +0xb5, 0x18, 0x00, 0xe0, 0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42, +0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43, +0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, +0x01, 0x1d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, +0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, +0x09, 0x68, 0x1e, 0x9a, 0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, +0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, +0x11, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, +0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, +0x17, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, +0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, +0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, +0x0b, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, +0xf8, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, +0x91, 0x42, 0x00, 0xdd, 0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, +0x01, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, +0x33, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, +0xe1, 0x6d, 0x41, 0x18, 0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, +0x72, 0x6a, 0x02, 0xf0, 0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, +0xb1, 0x6a, 0x81, 0x42, 0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, +0x2f, 0x23, 0x9b, 0x01, 0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, +0x92, 0x00, 0x27, 0x4b, 0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, +0x4a, 0x08, 0x05, 0xd3, 0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, +0x01, 0xf0, 0xd6, 0xff, 0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, +0x0b, 0x78, 0x00, 0x2b, 0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, +0x1e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, +0xc3, 0x18, 0x05, 0xce, 0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, +0xc7, 0xfe, 0x14, 0x48, 0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, +0x00, 0xd3, 0x25, 0x60, 0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, +0x3a, 0x6b, 0xc0, 0x46, 0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, +0x81, 0x68, 0x00, 0x29, 0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, +0x04, 0xe0, 0x39, 0x6b, 0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, +0xc0, 0x46, 0xc1, 0x60, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xea, 0x05, 0x00, 0x00, 0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, +0x68, 0x0e, 0x00, 0x80, 0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, +0x04, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, +0xff, 0x25, 0x01, 0x35, 0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, +0x01, 0x38, 0x78, 0x61, 0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, +0xc0, 0x46, 0xb8, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, +0x00, 0xf0, 0x04, 0xfa, 0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, +0xe9, 0xd1, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, +0x01, 0x31, 0xc1, 0x71, 0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, +0x28, 0x1b, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40, +0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47, +0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08, 0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30, 0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, -0x09, 0xfe, 0x01, 0x23, 0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, -0x00, 0x68, 0x16, 0x4c, 0x21, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, +0xf3, 0xfd, 0x01, 0x23, 0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, +0x00, 0x68, 0x16, 0x4c, 0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, -0x00, 0xf0, 0x22, 0xf8, 0x20, 0x62, 0x20, 0x6a, 0xe1, 0x69, 0x88, 0x42, +0x00, 0xf0, 0x22, 0xf8, 0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21, 0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, -0xf2, 0xd0, 0x51, 0x21, 0x89, 0x03, 0x22, 0x6a, 0xe3, 0x6a, 0x9a, 0x42, -0x02, 0xd1, 0x20, 0x6b, 0x62, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, +0xf2, 0xd0, 0x51, 0x21, 0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, +0x02, 0xd1, 0x60, 0x6b, 0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, -0x08, 0x60, 0xf7, 0xe7, 0xec, 0x05, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, -0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x01, 0x31, -0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x18, 0x0d, 0x30, -0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x04, 0x49, -0x4a, 0x6b, 0x12, 0x18, 0x0b, 0x6b, 0x9a, 0x42, 0x00, 0xd9, 0xc8, 0x6a, -0x70, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, 0x00, 0xb5, 0x04, 0x48, -0x80, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0, 0x05, 0xf8, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, 0x88, 0xb5, 0x0c, 0x4f, -0x38, 0x78, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49, 0x10, 0x20, 0x02, 0xf0, -0xfb, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20, 0x38, 0x70, 0x08, 0x4a, -0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68, 0x07, 0x4b, 0x01, 0x68, -0x00, 0x20, 0x02, 0xf0, 0xe5, 0xfd, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x78, 0x1a, 0x00, 0x80, 0x69, 0x2c, 0xff, 0xff, 0x10, 0x00, 0x35, 0x02, -0xf8, 0x28, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x90, 0xb5, 0x01, 0x20, -0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4f, 0x10, 0x21, -0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x52, 0xfc, 0x19, 0x23, 0xdb, 0x01, -0xfc, 0x18, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x14, 0xf8, -0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18, 0x08, 0x70, 0xa0, 0x68, -0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xf9, 0x18, -0x48, 0x72, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, -0xe8, 0x0d, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48, 0x19, 0x23, 0xdb, 0x01, -0xc1, 0x18, 0x89, 0x68, 0x35, 0x4d, 0x10, 0x29, 0x00, 0xd9, 0x10, 0x21, -0x29, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e, 0x81, 0x42, 0x07, 0xd9, -0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x28, 0x6a, 0xb8, 0x42, 0x12, 0xd2, -0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2, 0x2c, 0x4a, 0x52, 0x6b, -0x10, 0x1a, 0x07, 0x09, 0x28, 0x6a, 0xb8, 0x42, 0x05, 0xd9, 0x0c, 0x09, -0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b, 0x01, 0xe0, 0x00, 0x24, -0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49, 0x02, 0xf0, 0x8a, 0xfd, -0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c, 0x1a, 0xd1, 0x1e, 0x49, -0x3a, 0x01, 0x2f, 0x62, 0x09, 0x6e, 0x8c, 0x18, 0x1d, 0x4d, 0x6b, 0x6b, -0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b, 0x1a, 0x43, 0x00, 0x92, -0xea, 0x6a, 0x51, 0x18, 0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, -0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x00, 0x20, 0x28, 0x62, 0xf8, 0xbc, +0x08, 0x60, 0xf7, 0xe7, 0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, +0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, +0x09, 0x04, 0x09, 0x0c, 0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, +0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, +0x4b, 0x6b, 0x9a, 0x42, 0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, +0xe8, 0x1a, 0x00, 0x80, 0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, +0x01, 0xd3, 0x00, 0xf0, 0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xe8, 0x1a, 0x00, 0x80, 0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, +0x11, 0xd1, 0x0b, 0x49, 0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, +0x0b, 0xd0, 0x01, 0x20, 0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, +0x07, 0x48, 0x42, 0x68, 0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, +0xdf, 0xfd, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, +0xe1, 0x2c, 0xff, 0xff, 0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, +0x44, 0x80, 0x20, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, +0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, +0x02, 0xf0, 0x4c, 0xfc, 0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, +0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, +0x1b, 0x01, 0xf9, 0x18, 0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, +0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, +0xf8, 0xb5, 0x37, 0x48, 0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, +0x35, 0x4d, 0x10, 0x29, 0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, +0xc1, 0x6c, 0x00, 0x6e, 0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, +0x00, 0x24, 0x68, 0x6a, 0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, +0x81, 0x42, 0x2a, 0xd2, 0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, +0x68, 0x6a, 0xb8, 0x42, 0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, +0x03, 0xd2, 0xc4, 0x1b, 0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, +0x30, 0x01, 0x25, 0x49, 0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, +0x23, 0x48, 0x00, 0x2c, 0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, +0x09, 0x6e, 0x8c, 0x18, 0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, +0xe4, 0x1a, 0x1e, 0x4b, 0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18, +0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31, +0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, -0x52, 0x05, 0x3a, 0x43, 0x2e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, +0x52, 0x05, 0x3a, 0x43, 0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18, 0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, -0x02, 0xf0, 0x50, 0xfd, 0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, -0xe9, 0x6a, 0x2a, 0x6b, 0x00, 0x20, 0x02, 0xf0, 0x47, 0xfd, 0x03, 0x48, +0x02, 0xf0, 0x4a, 0xfd, 0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, +0xe9, 0x6a, 0x2a, 0x6b, 0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66, 0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, -0xe8, 0x0d, 0x00, 0x80, 0xa8, 0x1a, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, -0xd1, 0x2d, 0xff, 0xff, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, +0x68, 0x0e, 0x00, 0x80, 0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, +0x49, 0x2e, 0xff, 0xff, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40, 0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, -0xd1, 0x60, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, 0x81, 0x63, 0x70, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, -0x01, 0x20, 0x80, 0x02, 0x1c, 0x49, 0xc0, 0x46, -0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23, 0x9b, 0x01, 0xf5, 0x18, -0x28, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c, 0x68, 0x46, 0x10, 0x21, -0x02, 0xf0, 0x96, 0xfb, 0x68, 0x46, 0x00, 0xf0, 0x33, 0xf8, 0x00, 0x28, -0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x0a, 0xe0, -0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73, 0x88, 0x79, 0x01, 0x30, -0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x6b, 0xf9, 0x28, 0x6a, -0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23, 0x1b, 0x01, 0xf0, 0x18, -0x81, 0x7a, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21, 0x81, 0x72, 0xff, 0xf7, -0x1d, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, -0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40, 0xa0, 0x82, 0x20, 0x40, -0xd8, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f, 0x19, 0x23, 0xdb, 0x01, -0xf9, 0x18, 0x00, 0x22, 0x8b, 0x68, 0x00, 0x2b, 0x23, 0xd0, 0x01, 0x3b, -0x8b, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18, 0x7b, 0x69, 0x1c, 0x6d, -0xc0, 0x46, 0x7c, 0x61, 0x04, 0x68, 0xc0, 0x46, 0x5c, 0x60, 0x44, 0x68, -0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46, 0x1c, 0x61, 0xc0, 0x68, -0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0xc8, 0x68, 0x42, 0x1c, 0xca, 0x60, -0x00, 0x28, 0x03, 0xd0, 0xf8, 0x69, 0xc0, 0x46, 0x03, 0x65, 0x00, 0xe0, -0xbb, 0x61, 0xfb, 0x61, 0x18, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x10, 0x1c, -0xfb, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x0a, 0x4a, 0x33, 0x23, -0x9b, 0x01, 0xd1, 0x18, 0x88, 0x69, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, -0xd3, 0x68, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b, 0xd3, 0x60, 0x8a, 0x69, -0x12, 0x6d, 0xc0, 0x46, 0x8a, 0x61, 0x70, 0x47, 0x00, 0x21, 0xd1, 0x60, -0xfb, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68, -0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69, -0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00, -0x68, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0x91, 0x68, 0x4b, 0x1c, 0x93, 0x60, -0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x51, 0x69, 0x00, 0xe0, 0x00, 0x21, -0x01, 0x65, 0x50, 0x61, 0x70, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, -0x90, 0xb4, 0x00, 0x21, 0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, -0x1b, 0x18, 0x9b, 0x8a, 0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, +0xd1, 0x60, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, +0x01, 0x20, 0x80, 0x02, 0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, +0x1b, 0x4e, 0x33, 0x23, 0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, +0x1d, 0xd9, 0x19, 0x4c, 0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, +0x68, 0x46, 0x00, 0xf0, 0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, +0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, +0x01, 0x30, 0x60, 0x73, 0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, +0x00, 0x68, 0x02, 0xf0, 0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, +0xe2, 0xd8, 0xbb, 0x23, 0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, +0x03, 0xd0, 0x00, 0x21, 0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, +0xe3, 0xfe, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, +0x08, 0x83, 0x20, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, +0x90, 0xb4, 0x17, 0x4f, 0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, +0xcb, 0x68, 0x00, 0x2b, 0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, +0x9b, 0x01, 0xff, 0x18, 0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, +0x04, 0x68, 0xc0, 0x46, 0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, +0x84, 0x68, 0xc0, 0x46, 0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, +0x1a, 0x65, 0x08, 0x69, 0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, +0x38, 0x6a, 0xc0, 0x46, 0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, +0x18, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, +0xc8, 0x69, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, +0x06, 0xd0, 0x01, 0x3b, 0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, +0xca, 0x61, 0x70, 0x47, 0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, +0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, +0x01, 0x65, 0xd0, 0x61, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, +0x06, 0x4a, 0xd1, 0x68, 0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, +0x01, 0xd0, 0x91, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, +0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, +0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a, +0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0, 0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, -0x04, 0x29, 0xe4, 0xd3, 0x01, 0x20, 0xf8, 0xe7, 0xc8, 0x29, 0x00, 0x80, +0x04, 0x29, 0xe4, 0xd3, 0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0, 0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a, 0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40, 0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, @@ -1062,85 +1075,85 @@ 0x5d, 0xd9, 0x1c, 0x1c, 0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96, 0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92, 0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, -0x05, 0x9c, 0xe3, 0x40, 0x03, 0x9c, 0xa3, 0x42, -0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c, 0x63, 0x00, 0x1b, 0x19, -0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, -0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, -0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x51, 0x36, 0x33, 0x43, -0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96, 0x01, 0x23, 0x9b, 0x07, -0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x83, 0x42, 0x1b, 0xd1, -0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36, 0x33, 0x43, 0x1b, 0x68, -0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, -0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b, 0x32, 0x2b, 0x04, 0xd1, -0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14, 0x0f, 0xe0, 0x08, 0x9b, -0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0, 0x04, 0x9a, 0x01, 0x37, -0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a, 0x01, 0x35, 0xaa, 0x42, -0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xc8, 0x29, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, -0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28, 0x06, 0xd0, 0x26, 0x48, -0x00, 0x68, 0x02, 0xf0, 0x31, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f, 0x00, 0x28, 0x16, 0xd0, -0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, -0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0x08, 0xff, 0x00, 0x28, 0xea, 0xd1, -0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, -0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe9, 0xd0, 0x68, 0x68, -0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60, 0xfe, 0xf7, 0xd2, 0xfb, -0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28, 0xf6, 0xd1, 0x11, 0xe0, -0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, -0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7, 0xe3, 0xfe, 0x00, 0x28, -0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, -0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe7, 0xd0, -0xb9, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xdc, 0x03, 0x00, 0x80, -0xc8, 0x29, 0x00, 0x80, 0x0c, 0x06, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, -0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, -0x1d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x9f, 0xfc, 0x03, 0x23, +0x05, 0x9c, 0xe3, 0x40, 0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, +0xca, 0x40, 0x14, 0x1c, 0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, +0xd2, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, +0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, +0x9b, 0x07, 0xd6, 0x1d, 0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, +0x1e, 0x40, 0x00, 0x96, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, +0x33, 0x43, 0x1b, 0x68, 0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, +0xd6, 0x1d, 0x4d, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, +0x12, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, +0x12, 0x0c, 0x08, 0x9b, 0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, +0x20, 0x04, 0x00, 0x14, 0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, +0x01, 0x2a, 0xf7, 0xd0, 0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, +0x00, 0x27, 0x04, 0x9a, 0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, +0xc0, 0x43, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, +0x68, 0x69, 0x00, 0x28, 0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, +0x2b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, +0xa0, 0x68, 0x23, 0x4f, 0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, +0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, +0xfd, 0xf7, 0xe8, 0xfe, 0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, +0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, +0x38, 0x79, 0x00, 0x28, 0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, +0x01, 0x20, 0xa0, 0x60, 0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, +0x68, 0x68, 0x00, 0x28, 0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, +0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, +0xa6, 0x60, 0xfd, 0xf7, 0xc3, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, +0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, +0xbd, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, +0x6c, 0x06, 0x00, 0x80, 0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, +0x8c, 0x06, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, +0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46, +0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a, 0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65, 0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18, 0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18, 0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d, 0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, -0xfd, 0xf7, 0x10, 0xf8, 0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, +0xfc, 0xf7, 0xd4, 0xff, 0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, -0x01, 0xf0, 0xc8, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, +0x01, 0xf0, 0xc6, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20, 0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, -0x5b, 0xfc, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, -0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01, 0x80, 0x1b, 0x80, 0x00, -0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x78, 0x6a, -0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d, 0xe5, 0x63, 0xb9, 0x69, -0x28, 0x1c, 0x02, 0xf0, 0x8f, 0xf9, 0x38, 0x1c, 0x21, 0x1c, 0x32, 0x1c, -0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0xf0, 0xb5, 0x4b, 0x6f, -0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68, 0x00, 0x23, 0x84, 0x69, -0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59, 0xc0, 0x46, 0x3e, 0x51, -0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42, 0xf6, 0xd8, 0x3b, 0x1c, -0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xb5, -0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c, 0x46, 0x48, 0x01, 0x69, -0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31, 0xbd, 0x65, 0x00, 0x91, -0x20, 0x1c, 0xfd, 0xf7, 0xa3, 0xfc, 0xf8, 0x6d, 0x40, 0x09, 0x36, 0xd2, -0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02, 0x1e, 0x43, 0x17, 0x21, -0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73, 0x00, 0x99, 0x20, 0x1c, -0xfd, 0xf7, 0x92, 0xfc, 0xb8, 0x6d, 0xc0, 0x46, 0x06, 0x73, 0x33, 0x0a, -0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2, 0x60, 0x68, 0x01, 0x04, -0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xce, 0xfc, 0x60, 0x68, 0x32, 0x4b, -0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0, 0x37, 0xfd, 0x00, 0x25, -0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64, 0x20, 0x1c, 0xfc, 0xf7, -0x77, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0x7d, 0x62, -0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xa0, 0xfb, -0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, -0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68, 0x02, 0x04, 0x12, 0x0c, -0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31, 0x8a, 0x42, 0x02, 0xd2, -0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19, 0x89, 0x89, 0xf0, 0x23, -0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, -0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42, 0x16, 0xd2, 0x39, 0x64, -0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, -0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, -0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, +0x59, 0xfc, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, +0x06, 0x0f, 0x70, 0x01, 0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, +0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, +0x80, 0x6f, 0x05, 0x1d, 0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, +0x89, 0xf9, 0x38, 0x1c, 0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, +0x20, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, +0x5c, 0x2b, 0x00, 0x80, 0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, +0xcf, 0x63, 0x05, 0x68, 0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, +0x9c, 0x00, 0x2e, 0x59, 0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, +0x01, 0x33, 0x9c, 0x42, 0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, +0x1d, 0x1c, 0x0f, 0x1c, 0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, +0xf9, 0x1d, 0x51, 0x31, 0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, +0x67, 0xfc, 0xf8, 0x6d, 0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, +0x43, 0x7b, 0x1b, 0x02, 0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, +0x0b, 0x0a, 0x43, 0x73, 0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x56, 0xfc, +0xb8, 0x6d, 0xc0, 0x46, 0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, +0x40, 0x09, 0x20, 0xd2, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, +0x01, 0xf0, 0xcc, 0xfc, 0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, +0x20, 0x1c, 0x01, 0xf0, 0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, +0x3d, 0x64, 0x7d, 0x64, 0x20, 0x1c, 0xfc, 0xf7, 0x3b, 0xff, 0x38, 0x88, +0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, +0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, +0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, +0x78, 0x64, 0x60, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, +0xc1, 0x1d, 0x0d, 0x31, 0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, +0x0e, 0xe0, 0x41, 0x19, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, +0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, +0x09, 0x0c, 0x81, 0x42, 0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, +0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61, +0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b, +0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62, 0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18, 0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9, 0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, @@ -1148,127 +1161,127 @@ 0x82, 0x42, 0xf3, 0xd8, 0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, -0x01, 0x68, 0x78, 0x6c, 0xfc, 0xf7, 0xdb, 0xff, -0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0xf8, 0x68, 0x81, 0x42, -0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, -0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, -0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, -0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x5e, 0xfb, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68, 0x08, 0x1a, 0x78, 0x62, -0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xd9, 0xfb, 0x20, 0x1c, -0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7, 0xf0, 0xb5, 0x84, 0xb0, -0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, -0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40, 0x06, 0x0f, 0x0a, 0x04, -0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68, 0xd2, 0x1a, 0x7b, 0x68, -0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, -0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x2e, 0xfb, -0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c, 0x60, 0x60, 0x30, 0x1c, -0x01, 0xf0, 0xe2, 0xfb, 0x7d, 0x4e, 0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, -0xc0, 0x68, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25, 0x2d, 0x23, 0x9b, 0x01, -0xf0, 0x18, 0x80, 0x68, 0x00, 0x28, 0x12, 0xd0, 0xaa, 0x00, 0x92, 0x19, -0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x92, 0x68, 0x20, 0x1c, 0x39, 0x1c, -0x01, 0xf0, 0x22, 0xfe, 0x01, 0x35, 0xa8, 0x00, 0x80, 0x19, 0x2d, 0x23, -0x9b, 0x01, 0xc0, 0x18, 0x80, 0x68, 0x00, 0x28, 0xec, 0xd1, 0xf8, 0x6b, -0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68, 0x7d, 0x6c, 0x00, 0xf0, -0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c, 0xfc, 0xf7, -0x56, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e, 0x8e, 0x18, 0x20, 0x68, -0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18, 0x11, 0x18, 0x02, 0x91, -0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88, 0x08, 0x02, 0x09, 0x0a, -0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x78, 0x61, -0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, -0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, -0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89, 0x09, 0x23, 0x1b, 0x02, -0x18, 0x40, 0xb8, 0x61, 0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, -0x02, 0x99, 0xc0, 0x46, 0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, +0x01, 0x68, 0x78, 0x6c, 0xfc, 0xf7, 0x9f, 0xff, 0x78, 0x64, 0x60, 0x68, +0x01, 0x04, 0x09, 0x0c, 0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, +0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, +0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, +0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, +0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0xb9, 0x68, 0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, +0x38, 0x1c, 0x00, 0xf0, 0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, +0x01, 0xf8, 0xef, 0xe7, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, +0x8e, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, +0x61, 0x68, 0x08, 0x40, 0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, +0x11, 0x18, 0xfb, 0x68, 0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, +0x05, 0x3b, 0x38, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, +0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, +0x01, 0x04, 0x09, 0x0c, 0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, +0x7d, 0x4e, 0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, +0x19, 0xd0, 0x00, 0x25, 0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, +0x00, 0x28, 0x12, 0xd0, 0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, +0xd2, 0x18, 0xd2, 0x68, 0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, +0x01, 0x35, 0xa8, 0x00, 0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, +0xc0, 0x68, 0x00, 0x28, 0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, +0xfa, 0x63, 0xfa, 0x68, 0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, +0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c, 0xfc, 0xf7, 0x1a, 0xff, 0x03, 0x90, +0xf9, 0x6b, 0x3a, 0x6e, 0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, +0x7a, 0x6e, 0x8d, 0x18, 0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, +0xe0, 0x60, 0xb1, 0x88, 0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, +0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, +0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, +0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, +0x38, 0x61, 0xa8, 0x89, 0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61, +0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46, +0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60, 0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, -0x2e, 0xff, 0x38, 0x86, 0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, -0x49, 0xff, 0x78, 0x86, 0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, -0x0e, 0xff, 0x00, 0x90, 0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, +0xf2, 0xfe, 0x38, 0x86, 0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, +0x0d, 0xff, 0x78, 0x86, 0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, +0xd2, 0xfe, 0x00, 0x90, 0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04, 0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02, 0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42, 0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02, 0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, -0xfc, 0xf7, 0xe9, 0xfe, 0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, -0xe4, 0xfe, 0x06, 0x1c, 0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, -0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, -0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xd5, 0xfe, -0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61, 0x01, 0x9a, 0xc0, 0x46, -0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, -0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, -0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c, 0xfc, 0xf7, 0xbd, 0xfe, -0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61, 0xb9, 0x68, 0x00, 0x29, -0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69, 0x11, 0x43, 0x02, 0x9a, -0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7, 0xac, 0xfe, 0x20, 0x82, -0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, -0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, -0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x08, 0x82, 0x09, 0xe0, -0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, -0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81, 0x04, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, -0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69, 0x01, 0x22, 0x04, 0x99, -0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98, 0x43, 0x01, 0x18, 0x1a, -0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18, 0xe0, 0x6b, 0xc0, 0x46, -0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1, 0x00, 0x26, 0x26, 0xe0, -0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x04, 0x98, 0xfc, 0xf7, -0x4f, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69, 0x30, 0x43, 0x28, 0x61, -0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42, 0x00, 0xd2, 0x05, 0x1c, -0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a, 0x62, 0x6a, 0x10, 0x1a, -0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62, 0x20, 0x88, 0x48, 0x23, -0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1, 0x38, 0x1c, 0xfc, 0xf7, -0x5f, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60, 0x20, 0x1c, 0x00, 0xf0, -0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68, 0x09, 0x18, 0xc3, 0x1f, -0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, -0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68, 0x46, 0x19, 0x78, 0x68, -0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c, 0x01, 0xf0, 0x8a, 0xfa, -0x21, 0x6e, 0x00, 0x98, 0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, -0x00, 0x0c, 0x61, 0x6e, 0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, +0xfc, 0xf7, 0xad, 0xfe, 0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, +0xa8, 0xfe, 0x06, 0x1c, 0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, +0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, +0x81, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0x99, 0xfe, 0x79, 0x69, 0x01, 0x31, +0xc0, 0x43, 0x79, 0x61, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, +0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, +0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, +0x01, 0x43, 0x30, 0x1c, 0xfc, 0xf7, 0x81, 0xfe, 0x39, 0x69, 0x7a, 0x68, +0x89, 0x18, 0x39, 0x61, 0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, +0x89, 0x89, 0xba, 0x69, 0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, +0xb9, 0x69, 0xfc, 0xf7, 0x70, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, +0xf8, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, +0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, +0x21, 0x68, 0xc0, 0x46, 0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, +0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, +0xc0, 0x46, 0x88, 0x81, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x0c, 0x2b, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, +0x6e, 0x4d, 0x28, 0x69, 0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, +0x28, 0x61, 0x04, 0x98, 0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, +0x69, 0x49, 0x44, 0x18, 0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, +0x00, 0x28, 0x01, 0xd1, 0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, +0x01, 0x31, 0x41, 0x61, 0x04, 0x98, 0xfc, 0xf7, 0x13, 0xfd, 0x07, 0x1c, +0x03, 0xd1, 0x28, 0x69, 0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, +0x65, 0x68, 0xa8, 0x42, 0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, +0x16, 0xd2, 0x40, 0x1a, 0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, +0xa6, 0x60, 0xa6, 0x62, 0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, +0x0d, 0x1c, 0x09, 0xd1, 0x38, 0x1c, 0xfc, 0xf7, 0x23, 0xfd, 0x03, 0x20, +0x60, 0x80, 0x66, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, +0xe1, 0x68, 0x38, 0x68, 0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, +0x02, 0x39, 0x2a, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, +0xd7, 0xf9, 0xe0, 0x68, 0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, +0x04, 0x98, 0x31, 0x1c, 0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98, +0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e, +0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, -0x41, 0x80, 0x20, 0x8e, 0xfc, 0xf7, 0x11, 0xfe, 0x06, 0x1c, 0x60, 0x8e, -0x02, 0x99, 0xfc, 0xf7, 0x0c, 0xfe, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, +0x41, 0x80, 0x20, 0x8e, 0xfc, 0xf7, 0xd5, 0xfd, 0x06, 0x1c, 0x60, 0x8e, +0x02, 0x99, 0xfc, 0xf7, 0xd0, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, -0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xfd, 0xfd, +0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xc1, 0xfd, 0x61, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e, 0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, -0x71, 0x60, 0x03, 0x98, 0xfc, 0xf7, 0xe1, 0xfd, 0x21, 0x69, 0x49, 0x19, -0x21, 0x61, 0xa1, 0x68, 0x49, 0x1b, 0xa1, 0x60, -0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43, 0xb1, 0x81, 0xa1, 0x69, -0xfc, 0xf7, 0xd3, 0xfd, 0x38, 0x82, 0x61, 0x6e, 0x38, 0x68, 0x09, 0x18, -0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99, 0x04, 0x38, 0x00, 0xf0, -0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d, 0x41, 0x08, 0x16, 0xd3, -0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, -0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0xc8, 0x81, -0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, -0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0x48, 0x81, 0x05, 0xb0, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x3c, 0x2c, 0x00, 0x80, -0xc8, 0x2a, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x03, 0x1c, -0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04, 0x31, 0x1c, 0x1d, 0x1d, -0xfc, 0xf7, 0x97, 0xfd, 0x40, 0xc7, 0x02, 0x9a, 0xd1, 0x1c, 0x89, 0x08, -0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 0x0d, 0xd0, 0x21, 0x0c, -0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c, 0x16, 0x1c, 0xfc, 0xf7, -0x86, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, -0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x08, -0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32, 0x93, 0x08, 0x5a, 0x1e, -0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0, 0x13, 0x1c, 0x01, 0x3a, -0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5, 0x86, 0xb0, 0x17, 0x1c, -0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b, 0x06, 0x99, 0xc0, 0x46, -0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99, 0x89, 0x6b, 0xc0, 0x46, -0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0, 0x21, 0x68, 0xc0, 0x46, -0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91, 0xa1, 0x68, 0xc0, 0x46, -0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42, 0x08, 0xd2, 0x02, 0xad, -0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a, 0x00, 0x21, 0x02, 0xab, -0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88, 0xc9, 0x1b, 0x02, 0xab, -0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21, 0x49, 0x06, 0x07, 0x9b, -0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06, 0xdb, 0x0e, 0x08, 0xd0, -0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x2a, 0x04, 0xd1, -0x01, 0xe0, 0x02, 0x2a, 0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, -0x01, 0x43, 0x0a, 0x1c, 0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, -0x07, 0x9b, 0x01, 0xf0, 0x61, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, +0x71, 0x60, 0x03, 0x98, 0xfc, 0xf7, 0xa5, 0xfd, 0x21, 0x69, 0x49, 0x19, +0x21, 0x61, 0xa1, 0x68, 0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, +0xa2, 0x69, 0x11, 0x43, 0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x97, 0xfd, +0x38, 0x82, 0x61, 0x6e, 0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, +0xe2, 0x68, 0x00, 0x99, 0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, +0x78, 0x82, 0xe0, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, +0x78, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, +0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, +0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, +0x39, 0x68, 0xc0, 0x46, 0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, +0x0c, 0x2b, 0x00, 0x80, 0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, +0x1c, 0x68, 0x26, 0x04, 0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x5b, 0xfd, +0x40, 0xc7, 0x02, 0x9a, 0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, +0x02, 0x92, 0x00, 0x29, 0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, +0x0a, 0x43, 0x11, 0x1c, 0x16, 0x1c, 0xfc, 0xf7, 0x4a, 0xfd, 0x40, 0xc7, +0x02, 0x99, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, +0x89, 0x00, 0x03, 0x32, 0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, +0x08, 0xc9, 0x08, 0xc0, 0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, +0x70, 0x47, 0xff, 0xb5, 0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, +0x80, 0x6c, 0xc0, 0x1b, 0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, +0xc0, 0x05, 0x06, 0x99, 0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, +0x4c, 0x6b, 0x67, 0xe0, 0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, +0xc0, 0x46, 0x03, 0x91, 0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, +0x49, 0x88, 0xb9, 0x42, 0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, +0x49, 0x88, 0x7f, 0x1a, 0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, +0x02, 0xa9, 0x49, 0x88, 0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, +0x00, 0x27, 0x01, 0x21, 0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, +0x0d, 0xd0, 0xeb, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, +0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a, +0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c, +0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, +0x07, 0x9b, 0x01, 0xf0, 0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0, 0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, -0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x52, 0xff, +0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90, 0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60, 0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, @@ -1276,513 +1289,512 @@ 0x44, 0x63, 0x01, 0x98, 0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0, 0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, -0x09, 0x9b, 0x01, 0xf0, 0x25, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, -0xf8, 0x28, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02, 0x90, 0xb5, 0x0c, 0x1c, -0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, -0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0xcb, 0xfc, 0xc0, 0x43, 0xf9, 0x68, -0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68, 0x08, 0x1a, 0x38, 0x60, -0x38, 0x1c, 0x01, 0xf0, 0x8d, 0xf9, 0x38, 0x1c, 0xfc, 0xf7, 0xd2, 0xfb, -0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3, 0xca, 0x09, 0x1f, 0xd2, -0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80, 0x41, 0x80, 0x47, 0x6f, -0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71, 0xfa, 0x6d, 0xc0, 0x46, -0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60, 0x0c, 0x48, 0xc0, 0x46, -0x41, 0x63, 0x81, 0x6b, 0x49, 0x08, 0x49, 0x00, 0x81, 0x63, 0x01, 0x20, -0x00, 0xf0, 0xce, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x6d, 0xff, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, -0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8, 0xf3, 0xe7, 0x00, 0x00, -0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0x10, 0x1c, 0x0d, 0x1c, -0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0, 0x01, 0x68, 0xc0, 0x46, -0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68, 0xc0, 0x46, 0x79, 0x60, -0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68, 0xc0, 0x46, 0xf9, 0x60, -0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42, 0x02, 0xd8, 0x28, 0x1c, -0x00, 0xf0, 0xee, 0xff, 0x31, 0x1c, 0x01, 0x3e, 0x00, 0x29, 0xe5, 0xd1, -0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0xc1, 0x61, -0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 0x08, 0x60, 0x02, 0xe0, -0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60, 0x70, 0x47, 0x00, 0x00, -0x3c, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68, 0x00, 0x28, 0x02, 0xd0, -0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47, 0x3c, 0x2c, 0x00, 0x80, -0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1, -0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0x90, 0x67, 0xc8, 0x60, -0x70, 0x47, 0x00, 0x00, 0x3c, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68, -0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47, -0x3c, 0x2c, 0x00, 0x80, 0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, -0x08, 0x60, 0xff, 0xf7, 0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, +0x09, 0x9b, 0x01, 0xf0, 0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, +0x04, 0x00, 0x53, 0x02, 0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, +0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, +0xfc, 0xf7, 0x8f, 0xfc, 0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, +0x78, 0x8a, 0x39, 0x68, 0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, +0x8b, 0xf9, 0x38, 0x1c, 0xfc, 0xf7, 0x96, 0xfb, 0x20, 0x1c, 0xff, 0xf7, +0x33, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, +0x8a, 0x09, 0x21, 0xd3, 0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, +0x00, 0x21, 0x01, 0x80, 0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, +0x19, 0x32, 0x51, 0x71, 0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, +0xc0, 0x46, 0x10, 0x60, 0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, +0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, +0x38, 0x1c, 0x00, 0xf0, 0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x80, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, +0x00, 0xf0, 0xb0, 0xf8, 0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, +0xf0, 0xb5, 0x07, 0x1c, 0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, +0x00, 0x2b, 0x19, 0xd0, 0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, +0x0c, 0x19, 0x41, 0x68, 0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, +0xb9, 0x60, 0xc1, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, +0xe9, 0x6a, 0x81, 0x42, 0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, +0x31, 0x1c, 0x01, 0x3e, 0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, +0x00, 0x2a, 0x01, 0xd1, 0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, +0xd0, 0x61, 0x48, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, +0x03, 0x49, 0x08, 0x68, 0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, +0x0a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, +0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, +0xca, 0x68, 0xc0, 0x46, 0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, +0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, +0x82, 0x6f, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80, +0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7, +0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b, 0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7, 0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7, 0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb, 0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, -0x01, 0x65, 0xee, 0xe7, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, +0x01, 0x65, 0xee, 0xe7, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7, 0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88, 0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, -0xf8, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, -0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c, 0x22, 0x48, 0xc0, 0x46, -0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33, 0x41, 0x6d, 0x82, 0x6d, -0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68, 0x01, 0x23, 0x9b, 0x07, -0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1, 0x0c, 0xe0, 0x98, 0x42, -0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18, 0x00, 0xe0, 0x19, 0x1a, -0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20, 0x00, 0x28, 0x1f, 0xd0, -0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xb8, 0x6a, 0xf9, 0x6a, -0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xfb, 0x6a, -0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a, 0x01, 0xf0, 0xe8, 0xfd, -0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80, 0x38, 0x88, 0x40, 0x23, -0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7, 0x55, 0xff, 0x98, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, -0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x28, 0x03, 0x00, 0x80, -0x08, 0x00, 0x11, 0x02, 0xf8, 0x28, 0x00, 0x80, 0xb0, 0xb5, 0x40, 0x20, -0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 0xff, 0xfe, 0x07, 0x1c, -0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x05, 0x0f, 0x68, 0x01, -0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18, 0x20, 0x88, 0x02, 0x23, -0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08, 0x34, 0xd3, 0x40, 0x08, -0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c, 0x40, 0x18, 0xa0, 0x64, -0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d, 0x89, 0x18, 0xa1, 0x63, -0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x03, 0x23, 0x1b, 0x07, -0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68, 0x36, 0x31, 0x94, 0x29, -0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60, 0x38, 0x20, 0x03, 0xe0, -0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20, 0xb8, 0x61, 0x39, 0x68, -0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c, 0xcb, 0x1f, 0x05, 0x3b, -0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80, 0x38, 0x1c, 0xff, 0xf7, -0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xfc, 0xf7, -0x4d, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, -0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xef, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, -0x90, 0xb5, 0x00, 0x27, 0x0f, 0x4c, 0x0d, 0xe0, 0x02, 0x6b, 0x01, 0x3a, -0x02, 0x63, 0x00, 0x2a, 0x05, 0xdc, 0xc2, 0x6a, 0xc0, 0x46, 0x02, 0x63, -0x80, 0x6a, 0x01, 0xf0, 0xcc, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, -0x38, 0x01, 0x00, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x41, 0x6a, +0xf8, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, +0x98, 0xb5, 0x07, 0x1c, 0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, +0xc3, 0x1d, 0x41, 0x33, 0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, +0x00, 0x0b, 0x9c, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, +0x98, 0x42, 0x00, 0xd1, 0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, +0x59, 0x1a, 0x41, 0x18, 0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, +0x00, 0xd8, 0x00, 0x20, 0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, +0xc0, 0x46, 0x08, 0x60, 0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, +0x10, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, +0x03, 0x20, 0x39, 0x6a, 0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, +0x18, 0x43, 0x38, 0x80, 0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, +0x38, 0x1c, 0xff, 0xf7, 0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, +0x55, 0x55, 0x55, 0x55, 0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, +0x7c, 0x29, 0x00, 0x80, 0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, +0x08, 0x60, 0x00, 0xf0, 0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, +0x1b, 0x07, 0x18, 0x40, 0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, +0x26, 0x49, 0x44, 0x18, 0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, +0x20, 0x88, 0x41, 0x08, 0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, +0xa0, 0x6c, 0xe1, 0x6c, 0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, +0xa1, 0x6b, 0x22, 0x6d, 0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, +0xc0, 0x46, 0x60, 0x65, 0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, +0x78, 0x60, 0x61, 0x68, 0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, +0x18, 0x43, 0x78, 0x60, 0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, +0x78, 0x60, 0x94, 0x20, 0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, +0x12, 0x0c, 0x20, 0x1c, 0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, +0x02, 0x20, 0x60, 0x80, 0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xfc, 0xf7, 0x11, 0xfa, 0x28, 0x01, +0x06, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, +0x01, 0x39, 0x41, 0x63, 0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, +0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27, +0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, +0x42, 0x63, 0x00, 0x2a, 0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, +0xc0, 0x6a, 0x01, 0xf0, 0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, +0x38, 0x01, 0x00, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1, 0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, -0x08, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x00, 0x00, 0xb0, 0x11, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, -0x10, 0x49, 0xc8, 0x68, 0x01, 0x28, 0x19, 0xd1, 0xc8, 0x1d, 0x79, 0x30, -0x82, 0x88, 0x00, 0x2a, 0x14, 0xd0, 0x01, 0x3a, 0x82, 0x80, 0x82, 0x88, -0x00, 0x2a, 0x0f, 0xd1, 0xc2, 0x88, 0x00, 0x2a, 0x0a, 0xd1, 0x02, 0x23, -0xca, 0x6f, 0x1a, 0x43, 0xca, 0x67, 0x07, 0x49, 0xc0, 0x46, 0x0a, 0x60, -0x04, 0x21, 0x81, 0x80, 0x01, 0x21, 0x00, 0xe0, 0x00, 0x21, 0xc1, 0x80, -0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 0xb0, 0xb5, 0x07, 0x1c, -0x01, 0x23, 0xf8, 0x1d, 0x69, 0x30, 0x03, 0x73, 0x1d, 0x49, 0xca, 0x1d, -0x79, 0x32, 0xd4, 0x89, 0x60, 0x1c, 0xd0, 0x81, 0x55, 0x8a, 0x00, 0x20, -0xac, 0x42, 0x02, 0xdb, 0x53, 0x73, 0xd0, 0x81, 0x50, 0x83, 0x01, 0x23, -0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61, -0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46, -0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x61, 0x48, 0x69, -0xfa, 0x6c, 0x90, 0x43, 0x48, 0x61, 0x01, 0x21, 0x09, 0x05, 0xc8, 0x60, -0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a, -0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, -0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3, -0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23, -0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e, -0x38, 0x1c, 0x01, 0xf0, 0xcf, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1, -0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72, -0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d, -0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb4, 0xfc, 0x00, 0x20, 0xf8, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49, -0xc8, 0x1d, 0xb9, 0x30, 0xc2, 0x6a, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31, -0xcf, 0x60, 0xc1, 0x6a, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0xc1, 0x62, -0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22, -0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1, -0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18, -0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92, -0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0, -0x81, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e, -0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x77, 0xfc, 0x20, 0x6b, -0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8, -0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7, 0x44, 0x80, 0x20, 0x40, -0x04, 0x00, 0x1b, 0x02, 0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, -0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, -0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x27, 0x00, 0x2a, -0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x08, 0x49, -0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, -0x08, 0x1c, 0xff, 0xf7, 0x2f, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x00, 0x00, 0xb0, 0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, -0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49, 0xc0, 0x46, 0x08, 0x60, -0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48, 0xc4, 0x1d, 0xb9, 0x34, -0x21, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31, 0xc9, 0x68, 0x7a, 0x68, -0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x21, 0x6b, 0x89, 0x00, 0x08, 0x18, -0xc0, 0x30, 0xc1, 0x68, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, -0x01, 0xf0, 0xa6, 0xfa, 0x01, 0x23, 0x78, 0x68, -0x58, 0x40, 0x78, 0x60, 0x20, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f, -0x20, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1, -0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, -0x39, 0x48, 0x80, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68, -0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7, -0x9d, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31, -0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49, -0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0, -0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0, -0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09, -0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62, -0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0, -0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a, -0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19, -0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a, -0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62, -0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62, -0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1, -0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42, -0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19, -0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0, -0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38, -0x38, 0x61, 0x9e, 0xe7, 0xe8, 0x18, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, -0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90, -0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0x80, 0x6a, 0xc0, 0x46, -0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46, -0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60, -0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46, -0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a, 0xc1, 0x1b, 0x09, 0x09, -0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46, 0x0f, 0x93, 0xeb, 0x4b, -0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3, 0xb8, 0x42, 0x21, 0xd8, -0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, -0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0, 0x5b, 0xfb, 0x00, 0x28, -0x03, 0xd1, 0x0e, 0x9b, 0x98, 0x6b, 0x01, 0x30, 0x98, 0x63, 0x01, 0x20, -0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0xdd, 0x4a, 0xc0, 0x46, -0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0xdc, 0x4b, 0x00, 0x20, -0x01, 0xf0, 0x3e, 0xfb, 0x38, 0x1c, 0x5c, 0xe3, 0xb8, 0x42, 0x03, 0xd8, -0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c, 0xd7, 0x48, 0x80, 0x68, -0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, -0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x05, 0x90, -0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1, 0xe0, 0x6a, 0xc0, 0x1b, -0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2, -0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0, -0x87, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c, -0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68, -0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49, -0xc9, 0x68, 0x00, 0xf0, 0x74, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0, -0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x6d, 0xff, 0x7a, 0x68, 0xc0, 0x46, -0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49, -0x09, 0x68, 0x00, 0xf0, 0x62, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c, -0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x5b, 0xff, 0x10, 0x37, 0xe0, 0x6a, -0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c, -0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, -0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69, -0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a, -0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28, -0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f, -0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92, -0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48, -0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80, -0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, -0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, -0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, -0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18, -0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30, -0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61, -0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88, -0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0, -0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93, -0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68, -0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46, -0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, -0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49, 0x40, 0x18, 0x01, 0x9a, -0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0, 0x2a, 0xe0, 0x03, 0x93, -0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x12, 0x9a, 0x50, 0x78, -0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, -0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb, 0x07, 0x1c, 0x01, 0x9a, -0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18, 0x0b, 0x9b, 0x21, 0x1c, -0x3a, 0x1c, 0xff, 0xf7, 0x7b, 0xfb, 0x01, 0x9a, 0xc0, 0x46, 0xd0, 0x64, -0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65, 0x01, 0x23, 0x5b, 0x06, -0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 0x0d, 0xe0, +0x08, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, +0x00, 0x00, 0x00, 0xb0, 0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, +0x0f, 0x49, 0xc8, 0x68, 0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, +0x02, 0x89, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, +0x00, 0x2a, 0x0d, 0xd1, 0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, +0x02, 0x23, 0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, +0x01, 0x21, 0x00, 0xe0, 0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, +0x08, 0x83, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, +0x01, 0x23, 0xf8, 0x1d, 0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, +0x79, 0x32, 0x54, 0x8a, 0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, +0xac, 0x42, 0x04, 0xdb, 0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, +0xd1, 0x83, 0x01, 0x23, 0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, +0xc0, 0x46, 0xba, 0x61, 0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, +0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x79, 0x61, 0x41, 0x69, 0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, +0x00, 0x05, 0xc1, 0x60, 0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, +0xf9, 0x69, 0x41, 0x1a, 0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, +0x00, 0xf0, 0x0e, 0xf8, 0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, +0x81, 0x42, 0xe2, 0xd3, 0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, +0x0f, 0x1c, 0xff, 0x23, 0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, +0x21, 0x37, 0xe1, 0x6e, 0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, +0x00, 0x28, 0x13, 0xd1, 0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, +0x19, 0x43, 0x01, 0x72, 0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, +0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, +0x00, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, +0x20, 0x61, 0x23, 0x49, 0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, +0x51, 0x18, 0xc0, 0x31, 0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, +0x89, 0x0f, 0x01, 0x63, 0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, +0x03, 0xd8, 0x23, 0x22, 0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, +0x7e, 0x1a, 0x07, 0xd1, 0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, +0x61, 0x6e, 0x09, 0x18, 0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, +0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, +0x2b, 0x1c, 0x01, 0xf0, 0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, +0x00, 0x92, 0x61, 0x6e, 0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, +0x73, 0xfc, 0x20, 0x6b, 0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, +0x81, 0x42, 0x00, 0xd8, 0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7, +0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80, +0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, +0xc0, 0x03, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, +0x49, 0x30, 0x02, 0x7a, 0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, +0x08, 0x1c, 0xff, 0xf7, 0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, +0x02, 0x7a, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, +0x2d, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, +0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, +0x10, 0x20, 0x18, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, +0xf8, 0x60, 0x16, 0x48, 0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, +0x09, 0x18, 0xc0, 0x31, 0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, +0x51, 0x64, 0x61, 0x6b, 0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, +0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, +0x01, 0x23, 0x78, 0x68, 0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, +0x80, 0x07, 0x80, 0x0f, 0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, +0x00, 0x28, 0x02, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, +0x90, 0xb5, 0x07, 0x1c, 0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, +0xb8, 0x6a, 0xc0, 0x68, 0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, +0x78, 0x6f, 0xfc, 0xf7, 0x63, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, +0xf9, 0x1d, 0x19, 0x31, 0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0xf8, 0x6c, 0x2f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, +0x21, 0x1c, 0x00, 0xf0, 0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, +0x20, 0x1c, 0x00, 0xf0, 0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, +0x09, 0x18, 0x09, 0x09, 0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, +0x89, 0x1a, 0xa1, 0x62, 0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, +0x00, 0x2a, 0x07, 0xd0, 0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, +0x80, 0x00, 0xb9, 0x6a, 0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, +0x80, 0x00, 0xc0, 0x19, 0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, +0x41, 0x64, 0xb8, 0x6a, 0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, +0x40, 0x1a, 0xb8, 0x62, 0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, +0x40, 0x18, 0xb8, 0x62, 0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, +0x00, 0x29, 0xb8, 0xd1, 0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, +0x3a, 0x6c, 0x91, 0x42, 0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, +0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, +0x00, 0x28, 0x01, 0xd0, 0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, +0xa1, 0xd0, 0x01, 0x38, 0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, +0x00, 0x00, 0x00, 0xb0, 0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, +0x00, 0x20, 0x05, 0x90, 0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, +0xc0, 0x6a, 0xc0, 0x46, 0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, +0x49, 0x6b, 0xc0, 0x46, 0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, +0xc0, 0x46, 0xa8, 0x60, 0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, +0xf0, 0x48, 0xc0, 0x46, 0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a, +0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46, +0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, +0x91, 0x42, 0x01, 0xd3, 0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, +0x1e, 0xd2, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, +0x03, 0x99, 0x01, 0xf0, 0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, +0xd8, 0x6b, 0x01, 0x30, 0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, +0x68, 0x60, 0xaf, 0x61, 0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, +0x01, 0x6d, 0x42, 0x6d, 0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, +0x38, 0x1c, 0x5c, 0xe3, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, +0x7b, 0xfc, 0x07, 0x1c, 0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, +0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, +0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, +0x18, 0x40, 0x58, 0xd1, 0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, +0x88, 0x42, 0x02, 0xd2, 0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, +0x88, 0x68, 0x00, 0xf0, 0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, +0x28, 0x1c, 0x39, 0x1c, 0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, +0x2e, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, +0x03, 0xd0, 0xc1, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, +0x00, 0x28, 0x03, 0xd0, 0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, +0x7a, 0x68, 0xc0, 0x46, 0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, +0x30, 0x1c, 0xb8, 0x49, 0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, +0x17, 0xd1, 0x30, 0x1c, 0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, -0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, -0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99, 0x01, 0xf0, 0x2a, 0xfa, -0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c, -0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c, -0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x85, 0xfe, 0x41, 0x49, 0x00, 0x20, -0x01, 0xf0, 0x18, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0x98, 0x6b, -0x01, 0x30, 0x98, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, -0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a, -0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b, -0x00, 0x20, 0x01, 0xf0, 0xf7, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98, -0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90, -0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, -0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20, -0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90, -0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42, -0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90, -0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98, -0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42, -0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20, -0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1, -0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0, -0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb, -0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29, -0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a, -0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, -0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98, -0x83, 0x19, 0x1d, 0xe0, 0x68, 0x0e, 0x00, 0x80, 0x79, 0x48, 0xff, 0xff, -0xa8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0xf8, 0x28, 0x00, 0x80, -0x44, 0x80, 0x20, 0x40, 0xe8, 0x18, 0x00, 0x80, 0xe0, 0x03, 0x00, 0x80, -0x00, 0x00, 0x00, 0x80, 0xc8, 0x2a, 0x00, 0x80, 0xc9, 0x31, 0xff, 0xff, -0x58, 0x5f, 0x21, 0x40, 0x81, 0x3c, 0xff, 0xff, 0x41, 0x31, 0xff, 0xff, -0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, -0x6f, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98, 0x00, 0x28, 0x16, 0xd0, -0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1, 0x09, 0x23, 0x5b, 0x04, -0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98, 0xc2, 0x4a, 0x02, 0x43, -0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48, 0x01, 0x6d, 0x42, 0x6d, -0x00, 0x20, 0x01, 0xf0, 0x55, 0xf9, 0x00, 0x20, 0x02, 0x90, 0x08, 0x98, -0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b, 0x0b, 0x93, 0x10, 0x37, -0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x8a, 0xfa, -0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a, 0x80, 0x18, 0x78, 0x60, -0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80, 0x0a, 0x9a, 0x50, 0x1c, -0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98, 0x0a, 0x9a, 0x82, 0x42, -0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9, 0x53, 0xe7, 0xa8, 0x69, -0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09, 0x69, 0xd2, 0x08, 0x9a, -0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a, 0x8a, 0x42, 0x3e, 0xdb, -0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a, -0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a, -0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2, -0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, -0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, -0x05, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, -0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22, -0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d, -0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xf0, 0xf8, 0x00, 0x20, 0x02, 0x90, -0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, -0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a, +0x27, 0xfc, 0x07, 0x1c, 0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, +0x00, 0x20, 0xa8, 0x61, 0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, +0xb0, 0xe0, 0xa8, 0x69, 0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, +0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, +0xa4, 0xe0, 0x10, 0x28, 0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, +0x18, 0x40, 0x01, 0x0f, 0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, +0x82, 0x18, 0x01, 0x92, 0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, +0x2f, 0xd3, 0x9d, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, +0xc0, 0x46, 0x10, 0x80, 0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, +0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, +0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, +0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, +0x8f, 0x49, 0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, +0x50, 0x68, 0x36, 0x30, 0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, +0x94, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, +0x58, 0xe0, 0x7a, 0x88, 0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, +0x03, 0x90, 0x23, 0xe0, 0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, +0x1d, 0xd0, 0x03, 0x93, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, +0x50, 0x60, 0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, +0x01, 0x9a, 0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, +0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49, +0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, +0x02, 0xe0, 0x33, 0xe0, 0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, +0xc0, 0x46, 0x48, 0x71, 0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, +0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, +0x00, 0xf0, 0x92, 0xfb, 0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, +0x09, 0x01, 0x40, 0x18, 0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, +0x7d, 0xfb, 0x01, 0x9a, 0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, +0xc0, 0x46, 0x13, 0x65, 0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, +0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, +0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, +0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, +0xa8, 0x69, 0x03, 0x99, 0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, +0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, +0x04, 0xd3, 0x30, 0x1c, 0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, +0x41, 0x49, 0x00, 0x20, 0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, +0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, +0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, +0xaf, 0x61, 0x3a, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, +0x42, 0x6d, 0x39, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, +0x15, 0xe2, 0x05, 0x98, 0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, +0x0c, 0x90, 0x0b, 0x90, 0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, +0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, +0x00, 0x26, 0x00, 0x20, 0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, +0x01, 0x38, 0x0d, 0x90, 0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, +0x12, 0x0c, 0x90, 0x42, 0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, +0x00, 0x0c, 0x08, 0x90, 0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, +0x07, 0xd1, 0x0d, 0x98, 0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, +0x30, 0x18, 0x88, 0x42, 0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, +0x1c, 0xe0, 0x11, 0x20, 0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, +0x18, 0x40, 0x02, 0xd1, 0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, +0x89, 0x0f, 0x0f, 0xd0, 0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, +0x1e, 0x28, 0x09, 0xdb, 0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, +0x01, 0xe0, 0x02, 0x29, 0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, +0x0a, 0x9a, 0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, +0x18, 0x43, 0x06, 0x90, 0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, +0x00, 0x90, 0x04, 0x98, 0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, +0xed, 0x48, 0xff, 0xff, 0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, +0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, +0x60, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, +0x41, 0x32, 0xff, 0xff, 0x58, 0x5f, 0x21, 0x40, 0xf9, 0x3c, 0xff, 0xff, +0xb9, 0x31, 0xff, 0xff, 0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, +0x06, 0xca, 0x01, 0xf0, 0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98, +0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1, +0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, +0x06, 0x90, 0x06, 0x98, 0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, +0x83, 0x19, 0xc1, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, +0x51, 0xf9, 0x00, 0x20, 0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, +0x0b, 0x9b, 0x01, 0x3b, 0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, +0x0c, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, +0x78, 0x68, 0x07, 0x9a, 0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, +0x80, 0x1a, 0x78, 0x80, 0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, +0x0a, 0x92, 0x0c, 0x98, 0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, +0xb1, 0x42, 0x00, 0xd9, 0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, +0xa8, 0x68, 0x01, 0x09, 0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, +0x0c, 0x99, 0x0a, 0x9a, 0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, +0x0c, 0xd0, 0x08, 0x9a, 0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, +0x06, 0xdb, 0x1e, 0x2a, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, +0x02, 0x29, 0x02, 0xd2, 0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, -0x06, 0xca, 0x01, 0xf0, 0xd9, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37, -0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa, -0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46, -0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99, -0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0, -0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23, -0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07, -0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, -0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, -0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98, -0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92, -0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, -0x93, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28, -0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, -0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92, -0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, -0x01, 0xf0, 0x7a, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42, -0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98, -0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, -0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x68, 0x60, -0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0, 0x27, 0xe0, 0xa8, 0x68, -0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e, 0x15, 0xd2, 0x01, 0x9a, -0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b, 0x0b, 0x9b, 0x21, 0x1c, -0x3a, 0x1c, 0xff, 0xf7, 0x87, 0xf9, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, -0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63, 0x03, 0xe0, 0xe8, 0x6a, -0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68, 0x30, 0x43, 0x68, 0x60, -0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x1b, -0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, -0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0xc3, 0x1f, -0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, -0x27, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, -0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42, -0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5, -0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69, -0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a, -0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28, -0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c, -0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61, -0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61, -0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, -0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xce, 0xfa, -0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18, -0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xf8, 0x28, 0x00, 0x80, -0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0xe8, 0x0d, 0x00, 0x80, -0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, -0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0, -0x49, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68, -0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18, -0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0, -0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e, -0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xa9, 0x6b, 0x19, 0x43, 0xa9, 0x63, -0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e, -0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0x69, 0x6b, -0x01, 0x31, 0x69, 0x63, 0x08, 0x29, 0x07, 0xd3, 0x68, 0x63, 0x01, 0x20, -0x00, 0xf0, 0x86, 0xf8, 0xa8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xa8, 0x63, -0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18, -0x89, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c, -0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, -0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x4a, 0xfc, 0x20, 0x1c, 0x00, 0xf0, -0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, -0x1c, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30, 0x01, 0x79, 0x00, 0x29, -0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c, 0xff, 0xf7, 0x56, 0xfb, -0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68, 0x80, 0x00, 0xc2, 0x19, -0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a, 0x41, 0x78, 0x09, 0x01, -0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42, 0x05, 0xd3, 0x38, 0x1c, -0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, -0xff, 0xf7, 0x2a, 0xfa, 0xf8, 0xe7, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, -0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7, 0xb0, 0xb5, 0x87, 0xb0, -0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24, 0x13, 0x4d, -0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x40, 0x69, 0x00, 0x28, 0x17, 0xd0, -0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xd2, 0x18, -0x52, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x96, 0xfb, 0x00, 0x28, 0x09, 0xd1, -0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23, -0x1b, 0x02, 0xc0, 0x18, 0x40, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, -0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0, -0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18, -0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68, -0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x7b, 0x00, 0x2d, 0x13, 0xd0, -0x5b, 0x7b, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43, -0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68, -0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xe3, 0xfe, 0xb8, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7, -0x3c, 0xef, 0x20, 0x40, 0xf8, 0x28, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, -0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x4a, 0x68, 0x00, 0x2a, 0x01, 0xd1, -0x48, 0x60, 0x02, 0xe0, 0x8a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x88, 0x60, -0x70, 0x47, 0x00, 0x00, 0xa8, 0x0e, 0x00, 0x80, 0x03, 0x49, 0x48, 0x68, -0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x4a, 0x60, 0x70, 0x47, -0xa8, 0x0e, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40, -0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a, -0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46, -0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c, -0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18, -0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68, -0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60, -0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32, -0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61, -0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c, -0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff, -0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x80, 0xfe, 0x01, 0x20, 0xf9, 0x1d, -0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61, -0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, -0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x66, 0xfe, 0xb8, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02, 0xf8, 0x28, 0x00, 0x80, -0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, +0x06, 0xca, 0x01, 0xf0, 0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, +0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, +0x92, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, +0x8e, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, +0x00, 0x20, 0x02, 0x90, 0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, +0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, +0x00, 0xe0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, +0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, +0x36, 0x18, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, +0x00, 0xf0, 0x14, 0xfa, 0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, +0x0a, 0x98, 0xc0, 0x46, 0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, +0x0d, 0x98, 0x09, 0x99, 0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, +0x5f, 0xe0, 0x5e, 0xe0, 0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, +0xa9, 0x68, 0x8c, 0x23, 0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, +0x1a, 0x43, 0xb1, 0x07, 0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, +0x08, 0xd0, 0x1e, 0x2b, 0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, +0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, +0x02, 0x1c, 0x09, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, +0x1a, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, +0x06, 0xca, 0x01, 0xf0, 0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, +0x02, 0x98, 0x00, 0x28, 0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, +0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, +0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, +0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, +0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, +0x07, 0x1c, 0x09, 0x98, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90, +0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04, +0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, +0x7b, 0xfa, 0x28, 0xe0, 0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, +0x68, 0x68, 0x80, 0x0e, 0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, +0x01, 0x9a, 0x50, 0x6b, 0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, +0x89, 0xf9, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, +0xc0, 0x46, 0x93, 0x63, 0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, +0x5d, 0xfa, 0x68, 0x68, 0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, +0x05, 0xd9, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, +0xae, 0x61, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, +0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, +0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, +0x9b, 0x07, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, +0xe1, 0x69, 0x81, 0x42, 0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, +0x41, 0x1a, 0x01, 0xd5, 0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, +0x3f, 0xfb, 0xe1, 0x69, 0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, +0x24, 0xd3, 0x40, 0x1a, 0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, +0x20, 0x69, 0x02, 0x28, 0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, +0x41, 0x69, 0xe2, 0x6c, 0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, +0x99, 0x43, 0x81, 0x61, 0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, +0xc0, 0x46, 0x08, 0x61, 0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, +0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, +0xff, 0xf7, 0xcc, 0xfa, 0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, +0x05, 0x99, 0x40, 0x18, 0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, +0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, +0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, +0x08, 0x60, 0x00, 0xf0, 0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, +0xa0, 0x6f, 0x00, 0xf0, 0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, +0x48, 0x71, 0x79, 0x68, 0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, +0x24, 0x49, 0x40, 0x18, 0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, +0x01, 0x60, 0x36, 0xe0, 0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, +0x11, 0x60, 0x20, 0x4e, 0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, +0x19, 0x43, 0xe9, 0x63, 0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, +0xb9, 0x6a, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, +0x04, 0xd1, 0xa9, 0x6b, 0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, +0xa8, 0x63, 0x01, 0x20, 0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, +0x40, 0x00, 0xe8, 0x63, 0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, +0x1b, 0x02, 0xf1, 0x18, 0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, +0x04, 0xd2, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, +0x38, 0x1c, 0x00, 0xf0, 0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x10, 0xfc, +0x20, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30, +0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, +0x01, 0x71, 0x38, 0x1c, 0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, +0x0d, 0xd0, 0xb8, 0x68, 0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, +0x11, 0xd0, 0xb8, 0x6a, 0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, +0x10, 0x1a, 0x88, 0x42, 0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, +0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, +0xf8, 0xe7, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, +0xb8, 0x62, 0xf1, 0xe7, 0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, +0xc0, 0x46, 0x00, 0x90, 0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, +0xe8, 0x18, 0x80, 0x69, 0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, +0x52, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, +0x00, 0xf0, 0x92, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, +0x40, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, +0xea, 0xd1, 0x01, 0xe0, 0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, +0x9d, 0xf9, 0x07, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, +0x16, 0x49, 0x01, 0xd0, 0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, +0x0c, 0x22, 0xa4, 0x18, 0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, +0x1c, 0x22, 0x0b, 0x68, 0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, +0x00, 0x2d, 0x13, 0xd0, 0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, +0x5b, 0x06, 0x1a, 0x43, 0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, +0x00, 0x92, 0x4a, 0x68, 0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, +0xdf, 0xfe, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, +0x1a, 0x43, 0xf1, 0xe7, 0x3c, 0xef, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, +0xf8, 0x0e, 0x00, 0x80, 0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, +0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, +0xd0, 0x61, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, +0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, +0x8a, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, +0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, +0x0a, 0x69, 0x01, 0x3a, 0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, +0x53, 0x6b, 0xc0, 0x46, 0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, +0x49, 0x6c, 0x53, 0x6c, 0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, +0x92, 0x00, 0x52, 0x18, 0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, +0x3d, 0x30, 0x0a, 0x68, 0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, +0x9a, 0x1a, 0x02, 0x60, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, +0xca, 0x68, 0x01, 0x32, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, +0x40, 0x18, 0x0a, 0x61, 0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, +0xb8, 0xb5, 0x04, 0x1c, 0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, +0xff, 0xf7, 0xd9, 0xff, 0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, +0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, +0x00, 0x20, 0xa0, 0x61, 0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, +0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe, +0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, +0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, +0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, +0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, +0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, -0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 0x50, 0x2d, 0x00, 0x80, -0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, -0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, -0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, -0x50, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x03, 0x30, 0x80, 0x08, -0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, -0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, -0x0a, 0x71, 0x70, 0x47, 0x50, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71, -0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00, -0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d, -0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c, -0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42, -0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9, -0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, -0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8, -0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8, -0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7, -0xf0, 0x03, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58, -0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08, -0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68, -0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, -0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0, -0xd5, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0xf0, 0x03, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40, -0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40, -0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04, -0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a, -0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68, +0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, +0xa0, 0x82, 0x20, 0x40, 0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, +0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, +0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, +0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, +0x01, 0x31, 0x41, 0x71, 0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, +0x90, 0xb4, 0x82, 0x00, 0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, +0x89, 0x08, 0x0b, 0x1d, 0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, +0xd7, 0x68, 0x12, 0x4c, 0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, +0x03, 0xd1, 0x81, 0x42, 0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, +0xb9, 0x42, 0x09, 0xd9, 0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, +0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, +0x81, 0x42, 0x05, 0xd8, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, +0x98, 0x42, 0x02, 0xd8, 0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, +0x05, 0x30, 0xfa, 0xe7, 0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, +0x0f, 0x4a, 0x17, 0x58, 0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, +0x01, 0xe0, 0x88, 0x08, 0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, +0x09, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, -0xf8, 0x68, 0x00, 0xf0, 0xa9, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69, -0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c, -0xfe, 0xf7, 0xc8, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79, -0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30, -0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7, -0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0x03, 0x00, 0x80, -0x3c, 0x2c, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, -0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x78, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68, -0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, 0x49, 0x08, 0x02, 0xd3, -0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21, 0x09, 0x04, 0x0c, 0xc8, -0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a, 0x03, 0xd3, 0x43, 0x68, -0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, -0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c, 0x00, 0x19, 0x23, 0x68, -0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28, 0x10, 0xd1, 0x60, 0x68, -0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x01, -0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, -0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x01, 0x00, 0x19, -0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0x5d, 0x1c, 0x05, 0x63, -0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18, 0x80, 0x33, 0x19, 0x63, -0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x21, 0xb9, 0x40, -0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b, 0x80, 0x29, 0xe2, 0xd3, -0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00, -0xa8, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, -0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24, -0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68, -0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60, -0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b, -0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19, -0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b, -0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f, -0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68, -0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c, -0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, -0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2f, 0x4b, -0x2f, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62, -0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c, -0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31, -0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29, -0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c, -0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00, -0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61, -0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3, -0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x17, 0x4f, 0x3a, 0x6f, 0xfd, 0x68, -0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0e, 0xd1, 0xdb, 0x6d, 0x5b, 0x08, -0x0b, 0xd3, 0x8b, 0x88, 0x00, 0x2b, 0x08, 0xd1, 0x03, 0x3b, 0xfd, 0x6f, -0x2b, 0x40, 0xfb, 0x67, 0x0f, 0x4d, 0xc0, 0x46, 0x2b, 0x60, 0x14, 0x23, -0x8b, 0x80, 0x10, 0x60, 0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, -0x00, 0xd0, 0x01, 0x38, 0x50, 0x60, 0xc9, 0x69, 0x08, 0x32, 0x91, 0x42, -0x00, 0xd8, 0x08, 0x4a, 0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, -0x82, 0x61, 0x3a, 0x67, 0xbc, 0xe7, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, -0x1c, 0x1c, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, -0x24, 0xa7, 0x20, 0x40, 0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, -0xc0, 0x05, 0x16, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, +0x38, 0x69, 0x00, 0xf0, 0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, +0x09, 0x07, 0x01, 0x40, 0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, +0x92, 0x07, 0x02, 0x40, 0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, +0x89, 0x0f, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, +0x01, 0x30, 0x00, 0x2a, 0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, +0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, +0xf9, 0x60, 0x81, 0x00, 0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, +0x0f, 0x48, 0x00, 0x69, 0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, +0x02, 0xd0, 0x20, 0x1c, 0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, +0x19, 0x30, 0x03, 0x79, 0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, +0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, +0x08, 0x1c, 0xff, 0xf7, 0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x70, 0x04, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, +0xe4, 0x2c, 0x00, 0x80, 0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, +0x03, 0xd1, 0x41, 0x68, 0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, +0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21, +0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, +0x87, 0x68, 0xbb, 0x0a, 0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, +0x01, 0x31, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, +0xf8, 0x00, 0x1d, 0x4c, 0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, +0x00, 0x79, 0x01, 0x28, 0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, +0x10, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, +0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, +0xc0, 0x18, 0x03, 0x6b, 0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, +0xdb, 0x00, 0xeb, 0x18, 0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, +0x01, 0x31, 0x81, 0x63, 0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, +0x21, 0x60, 0x01, 0x6b, 0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, +0xdf, 0xe7, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, +0x36, 0xd1, 0x00, 0x24, 0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, +0xb0, 0x60, 0x32, 0x68, 0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, +0x00, 0xd3, 0xb4, 0x60, 0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, +0xc0, 0x18, 0x87, 0x6b, 0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, +0xaa, 0x02, 0x92, 0x19, 0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, +0xca, 0x6a, 0x09, 0x6b, 0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, +0xc4, 0x62, 0x00, 0x2f, 0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, +0xdb, 0x43, 0x37, 0x68, 0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, +0x43, 0x63, 0x10, 0x1c, 0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, +0x00, 0x28, 0xc9, 0xd0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, +0x00, 0x27, 0x2e, 0x4b, 0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, +0x01, 0x30, 0xd8, 0x62, 0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, +0x02, 0x69, 0x53, 0x1c, 0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, +0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, +0x07, 0x61, 0x0f, 0x29, 0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x08, 0x1c, 0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, +0x6e, 0x1c, 0xad, 0x00, 0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, +0x01, 0x35, 0x55, 0x61, 0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, +0x0f, 0x2d, 0x00, 0xd3, 0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, +0x3a, 0x6f, 0xfd, 0x68, 0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, +0xdb, 0x6d, 0x5b, 0x08, 0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, +0xfd, 0x6f, 0x03, 0x3b, 0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, +0x0b, 0x81, 0x10, 0x60, 0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, +0x00, 0xd0, 0x01, 0x38, 0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, +0x00, 0xd8, 0x07, 0x4a, 0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, +0x82, 0x61, 0x3a, 0x67, 0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, +0xa0, 0x1c, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, +0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49, +0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f, 0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, -0x00, 0x19, 0xe1, 0x60, 0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x90, 0xfe, +0x00, 0x19, 0xe1, 0x60, 0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28, 0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69, 0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0, 0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, -0x65, 0x60, 0x20, 0x68, 0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x22, 0xff, +0x65, 0x60, 0x20, 0x68, 0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, -0x1c, 0x1c, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, +0xa0, 0x1c, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23, 0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, -0x02, 0x68, 0x15, 0x68, 0x13, 0x1d, 0x80, 0xcb, -0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2, 0x80, 0xc2, 0x08, 0xc2, -0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x04, 0x32, 0x1a, 0x43, -0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, -0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3, 0x1b, 0x4b, 0x1a, 0x40, -0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68, 0x1d, 0x68, 0x1f, 0x1d, -0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60, 0x20, 0xc3, 0x10, 0xc3, -0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d, 0x01, 0x23, 0x9b, 0x07, -0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f, 0xc8, 0x63, 0x80, 0xcb, -0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d, 0x04, 0x60, 0x38, 0x1c, -0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d, 0x43, 0x68, 0x1c, 0x04, -0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60, 0x40, 0x68, 0x00, 0x0c, -0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e, 0x04, 0x30, 0x08, 0x66, -0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20, 0xf0, 0xbc, 0x70, 0x47, -0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a, 0x01, 0x23, 0x9b, 0x07, -0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0xcf, 0x1d, 0x01, 0x37, -0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60, 0x01, 0x23, 0x9b, 0x07, -0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x60, 0x01, 0x23, -0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1, 0x02, 0x62, 0x01, 0x6b, -0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69, 0x19, 0x43, 0x81, 0x61, -0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a, 0x04, 0x31, 0x81, 0x62, -0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d, 0x39, 0x31, 0x4a, 0x8b, -0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b, 0x40, 0x32, 0x51, 0x83, -0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68, 0x00, 0x6b, 0xc0, 0x46, -0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x47, 0x08, 0x47, -0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47, 0x30, 0x47, 0x38, 0x47, -0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5, 0x0c, 0x48, 0xa0, 0xe1, -0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a, 0x01, 0xc0, 0x4c, 0xe2, -0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5, 0x94, 0x50, 0x20, 0xe0, -0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, -0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, -0x10, 0x10, 0x90, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, -0x0c, 0x50, 0x90, 0x55, 0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, +0x02, 0x68, 0x15, 0x68, 0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, +0x02, 0x60, 0x20, 0xc2, 0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, +0x01, 0x23, 0x9b, 0x07, 0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, +0xb0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, +0x53, 0x09, 0x34, 0xd3, 0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, +0x16, 0x43, 0x03, 0x68, 0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, +0x04, 0x3b, 0x03, 0x60, 0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, +0x43, 0x68, 0x1f, 0x1d, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, +0xcb, 0x6b, 0x18, 0x1f, 0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, +0x1f, 0x1d, 0x03, 0x1d, 0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, +0x1f, 0x60, 0x1f, 0x1d, 0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, +0x23, 0x43, 0x3b, 0x60, 0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, +0x78, 0x60, 0x08, 0x6e, 0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, +0x48, 0x66, 0x00, 0x20, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, +0x80, 0xb4, 0x81, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, +0x1a, 0x43, 0x12, 0x68, 0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, +0xc0, 0x46, 0xcb, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, +0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, +0x1b, 0x68, 0x0c, 0xc1, 0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, +0x04, 0x23, 0x81, 0x69, 0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, +0x91, 0x61, 0x81, 0x6a, 0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, +0x91, 0x62, 0xc1, 0x1d, 0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, +0x49, 0x8b, 0x02, 0x6b, 0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, +0xc1, 0x81, 0xc1, 0x68, 0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, +0x80, 0xbc, 0x70, 0x47, 0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, +0x20, 0x47, 0x28, 0x47, 0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, +0x0c, 0xc0, 0x9d, 0xe5, 0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, +0x1e, 0x00, 0x00, 0x0a, 0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, +0x64, 0x51, 0x9f, 0xe5, 0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, +0x14, 0x40, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, +0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5, +0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, +0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5, 0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5, 0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, @@ -1793,39 +1805,39 @@ 0x50, 0x10, 0x91, 0xe5, 0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5, 0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a, 0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, -0x94, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x80, 0xe0, -0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5, 0x00, 0x70, 0xa0, 0xe3, -0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x50, 0x90, 0xe5, -0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, -0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, -0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, -0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a, 0x03, 0x70, 0x17, 0xe2, -0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2, 0x0a, 0x00, 0x00, 0x0a, -0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2, 0x09, 0x00, 0x00, 0x0a, -0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3, 0xec, 0xff, 0xff, 0xca, -0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2, 0x02, 0xc4, 0x8c, 0xe3, -0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea, 0x00, 0x50, 0x88, 0xe5, -0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x50, 0x80, 0xe5, -0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, -0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1, 0x14, 0xa0, 0x80, 0xe5, -0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3, 0xf5, 0xff, 0xff, 0xea, -0x28, 0x03, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0x00, 0x80, 0x20, 0x40, -0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3, 0x64, 0xa2, 0x9f, 0xe5, -0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, -0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0x4f, 0xe1, -0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3, 0x54, 0x00, 0x00, 0x0a, -0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, -0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5, 0x09, 0x00, 0x00, 0xea, -0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b, 0x80, 0x00, 0x14, 0xe3, -0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, -0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x01, 0x06, 0x14, 0xe3, -0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3, 0x45, 0x00, 0x00, 0x1b, -0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b, 0x02, 0x08, 0x14, 0xe3, -0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3, 0x07, 0x00, 0x00, 0x0a, -0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5, 0x04, 0x30, 0x52, 0xe2, -0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5, 0x02, 0x00, 0x91, 0xe7, -0x0f, 0xe0, 0xa0, 0xe1, 0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, -0x03, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, +0x94, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, +0x04, 0x80, 0x90, 0xe5, 0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, +0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, +0x14, 0xa0, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, +0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, +0x09, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, +0x15, 0x00, 0x00, 0x0a, 0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, +0x20, 0x30, 0x83, 0xe2, 0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, +0x01, 0x70, 0x87, 0xe2, 0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, +0x20, 0x00, 0x56, 0xe3, 0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, +0x01, 0xc0, 0x46, 0xe2, 0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, +0xe7, 0xff, 0xff, 0xea, 0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, +0x00, 0x10, 0xa0, 0xe3, 0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, +0xf0, 0x47, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, +0x0a, 0x00, 0x55, 0xe1, 0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, +0x01, 0x10, 0xa0, 0xe3, 0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, +0x7c, 0x29, 0x00, 0x80, 0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, +0x0b, 0x92, 0xa0, 0xe3, 0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, +0x0e, 0xf0, 0xa0, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, +0x3f, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, +0x12, 0x00, 0x50, 0xe3, 0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, +0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, +0x00, 0x40, 0x99, 0xe5, 0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, +0x53, 0x00, 0x00, 0x1b, 0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, +0x20, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, +0x59, 0x00, 0x00, 0x1b, 0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, +0x08, 0x00, 0x14, 0xe3, 0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, +0x4a, 0x00, 0x00, 0x1b, 0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, +0xe5, 0x0e, 0x14, 0xe3, 0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, +0x0c, 0x10, 0x98, 0xe5, 0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, +0x04, 0x30, 0x88, 0xe5, 0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1, +0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a, +0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, @@ -1836,38 +1848,39 @@ 0x04, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3, 0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3, 0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, -0x01, 0x02, 0x14, 0xe3, 0x4c, 0x00, 0x9a, 0x15, -0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3, 0x50, 0x00, 0x9a, 0x15, -0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3, 0x21, 0x00, 0x00, 0x1b, -0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x9a, 0xe5, -0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b, 0x00, 0x40, 0x99, 0xe5, -0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2, 0x1b, 0xff, 0x2f, 0x11, -0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, 0xc0, 0x00, 0x80, 0xe3, -0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea, 0x18, 0x00, 0x9a, 0xe5, -0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, -0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, -0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x11, 0xff, 0x2f, 0xe1, -0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x28, 0x10, 0x9a, 0xe5, -0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, -0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x34, 0x10, 0x9a, 0xe5, -0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea, 0x38, 0xe0, 0x9a, 0xe5, -0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, -0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, -0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5, 0x00, 0x30, 0x92, 0xe5, -0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba, 0x00, 0x30, 0x82, 0xe5, -0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5, 0x00, 0x10, 0x91, 0xe2, -0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7, 0x04, 0x30, 0x53, 0xe2, -0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5, 0x01, 0x00, 0xa0, 0xe3, -0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, -0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, -0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0x90, 0xe5, -0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3, 0x08, 0x10, 0x80, 0xe5, -0x1e, 0xff, 0x2f, 0xe1, 0x50, 0x2d, 0x00, 0x80, 0x4c, 0x04, 0x00, 0x80, -0xe5, 0x2a, 0xff, 0xff, 0x45, 0x3d, 0xff, 0xff, 0x3d, 0x2b, 0xff, 0xff, -0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08, 0x89, 0x00, 0x01, 0x23, -0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68, 0x5b, 0x18, 0x13, 0x60, -0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47, 0x04, 0x20, 0xa0, 0xe5, +0x01, 0x02, 0x14, 0xe3, 0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, +0x01, 0x04, 0x14, 0xe3, 0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, +0x01, 0x0a, 0x14, 0xe3, 0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, +0x0e, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, +0x1c, 0x00, 0x00, 0x1b, 0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, +0x00, 0x40, 0x94, 0xe2, 0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, +0x04, 0xf0, 0x5e, 0xe2, 0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, +0xfa, 0xff, 0xff, 0xea, 0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, +0x11, 0xff, 0x2f, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, +0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, +0x00, 0x00, 0xa0, 0xe3, 0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, +0x11, 0xff, 0x2f, 0xe1, 0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, +0x2c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, +0x11, 0xff, 0x2f, 0xe1, 0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, +0xfe, 0xff, 0xff, 0xea, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, +0x18, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, +0x3c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, +0x64, 0x20, 0x9f, 0xe5, 0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, +0x0a, 0x00, 0x00, 0xba, 0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, +0x08, 0x30, 0x92, 0xe5, 0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, +0x03, 0x10, 0x80, 0xe7, 0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, +0x08, 0x30, 0x82, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, +0x3c, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, +0x00, 0x00, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, +0x10, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, +0x3c, 0x10, 0xa0, 0xb3, 0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, +0xe4, 0x2d, 0x00, 0x80, 0xcc, 0x04, 0x00, 0x80, 0x5d, 0x2b, 0xff, 0xff, +0xbd, 0x3d, 0xff, 0xff, 0xb5, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, +0xc9, 0x1c, 0x89, 0x08, 0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, +0x18, 0x43, 0x13, 0x68, 0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, +0x5b, 0x1a, 0x18, 0x47, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, +0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, @@ -1879,7 +1892,6 @@ 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, -0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, @@ -1909,9 +1921,9 @@ 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, -0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, -0x50, 0x2d, 0x00, 0x80, 0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, -0x01, 0x20, 0x40, 0xe0, 0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, +0x04, 0x20, 0xa0, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80, +0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, +0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, @@ -1922,125 +1934,125 @@ 0x4c, 0x00, 0x9f, 0xe5, 0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, -0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, -0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, -0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, -0x40, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0x80, 0x34, 0x00, 0x80, -0x44, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80, 0x40, 0x38, 0x00, 0x80, -0x48, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00, 0x91, 0xea, 0xff, 0xea, -0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, -0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xea, -0x78, 0x47, 0x00, 0x00, 0x8b, 0xea, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, -0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x28, 0x04, 0x00, 0x00, -0x61, 0x6d, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, -0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54, 0x03, 0x00, 0x00, 0x00, -0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x05, 0xff, 0xff, -0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00, 0xb5, 0x04, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff, 0x05, 0xff, 0x05, 0x54, -0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, -0x55, 0x05, 0xff, 0xff, 0x00, 0xff, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, -0xf5, 0x17, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0e, 0xff, 0xff, -0x01, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x02, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff, 0xff, 0xff, 0x01, 0x44, -0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x65, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, -0xbd, 0x4f, 0xff, 0xff, 0x01, 0x50, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, -0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, +0x00, 0x20, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, +0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, +0xfc, 0x37, 0x00, 0x80, 0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, +0xfc, 0x3f, 0x00, 0x80, 0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, +0x78, 0x47, 0x00, 0x00, 0x76, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, +0x39, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, +0x78, 0x47, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, +0x70, 0xea, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, +0x00, 0x00, 0x00, 0x80, 0x28, 0x04, 0x00, 0x00, 0x95, 0x22, 0x00, 0x00, +0x00, 0x01, 0x00, 0x80, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xb9, 0x0b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, +0x03, 0xff, 0x06, 0x54, 0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, +0x03, 0x00, 0x00, 0x00, 0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xf1, 0x05, 0xff, 0xff, 0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, +0x39, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, +0x01, 0xff, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, +0x00, 0x00, 0x00, 0x00, 0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xf1, 0x02, 0xff, 0xff, 0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, +0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x50, 0xff, 0xff, +0x6d, 0x50, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x80, -0x19, 0x78, 0x21, 0x40, 0x23, 0x78, 0x21, 0x40, 0x39, 0x78, 0x21, 0x40, -0x51, 0x78, 0x21, 0x40, 0x5d, 0x78, 0x21, 0x40, 0x6b, 0x78, 0x21, 0x40, -0x85, 0x78, 0x21, 0x40, 0xb1, 0x78, 0x21, 0x40, 0x75, 0x79, 0x21, 0x40, +0x00, 0x00, 0x00, 0x00, 0x48, 0x05, 0x00, 0x80, 0x19, 0x78, 0x21, 0x40, +0x23, 0x78, 0x21, 0x40, 0x39, 0x78, 0x21, 0x40, 0x51, 0x78, 0x21, 0x40, +0x5d, 0x78, 0x21, 0x40, 0x6b, 0x78, 0x21, 0x40, 0x85, 0x78, 0x21, 0x40, +0xb1, 0x78, 0x21, 0x40, 0x75, 0x79, 0x21, 0x40, 0xcd, 0x79, 0x21, 0x40, 0xdb, 0x79, 0x21, 0x40, 0xe5, 0x79, 0x21, 0x40, -0xef, 0x79, 0x21, 0x40, 0x81, 0x7a, 0x21, 0x40, 0x8f, 0x7a, 0x21, 0x40, -0x9d, 0x7a, 0x21, 0x40, 0x35, 0x7b, 0x21, 0x40, 0x03, 0x7f, 0x21, 0x40, -0x71, 0x7f, 0x21, 0x40, 0x19, 0x80, 0x21, 0x40, 0x4d, 0x81, 0x21, 0x40, -0x59, 0x81, 0x21, 0x40, 0xb9, 0x81, 0x21, 0x40, 0x1d, 0x82, 0x21, 0x40, -0x49, 0x82, 0x21, 0x40, 0x6d, 0x82, 0x21, 0x40, 0xad, 0x82, 0x21, 0x40, -0xd5, 0x82, 0x21, 0x40, 0x1d, 0x83, 0x21, 0x40, 0x2d, 0x83, 0x21, 0x40, -0x55, 0x83, 0x21, 0x40, 0x65, 0x83, 0x21, 0x40, 0xad, 0x83, 0x21, 0x40, -0xeb, 0x83, 0x21, 0x40, 0x41, 0x84, 0x21, 0x40, 0xa1, 0x84, 0x21, 0x40, -0xab, 0x84, 0x21, 0x40, 0xaf, 0x84, 0x21, 0x40, 0x1d, 0x85, 0x21, 0x40, -0x75, 0x85, 0x21, 0x40, 0xcd, 0x85, 0x21, 0x40, -0x09, 0x86, 0x21, 0x40, 0x6d, 0x86, 0x21, 0x40, 0xa5, 0x86, 0x21, 0x40, -0xb5, 0x86, 0x21, 0x40, 0xed, 0x86, 0x21, 0x40, 0xfd, 0x86, 0x21, 0x40, -0x11, 0x87, 0x21, 0x40, 0x39, 0x87, 0x21, 0x40, 0x43, 0x87, 0x21, 0x40, -0x4d, 0x87, 0x21, 0x40, 0x57, 0x87, 0x21, 0x40, 0xc1, 0x87, 0x21, 0x40, -0xcd, 0x87, 0x21, 0x40, 0x41, 0x88, 0x21, 0x40, 0x4b, 0x88, 0x21, 0x40, -0x55, 0x88, 0x21, 0x40, 0x5f, 0x88, 0x21, 0x40, 0x69, 0x88, 0x21, 0x40, -0x73, 0x88, 0x21, 0x40, 0x7d, 0x88, 0x21, 0x40, 0x87, 0x88, 0x21, 0x40, -0x91, 0x88, 0x21, 0x40, 0x9b, 0x88, 0x21, 0x40, 0xa5, 0x88, 0x21, 0x40, -0xaf, 0x88, 0x21, 0x40, 0xb9, 0x88, 0x21, 0x40, 0xc3, 0x88, 0x21, 0x40, -0xeb, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40, 0x51, 0x89, 0x21, 0x40, -0x5b, 0x89, 0x21, 0x40, 0x65, 0x89, 0x21, 0x40, 0x6f, 0x89, 0x21, 0x40, -0x79, 0x89, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0x83, 0x89, 0x21, 0x40, -0xe9, 0x89, 0x21, 0x40, 0x35, 0x8a, 0x21, 0x40, 0x81, 0x8a, 0x21, 0x40, -0x91, 0x8a, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xdd, 0x8a, 0x21, 0x40, -0xe1, 0x8a, 0x21, 0x40, 0xe5, 0x8a, 0x21, 0x40, 0x3d, 0x8b, 0x21, 0x40, -0x65, 0x8b, 0x21, 0x40, 0x71, 0x8b, 0x21, 0x40, 0x75, 0x8b, 0x21, 0x40, -0x79, 0x8b, 0x21, 0x40, 0xe9, 0x8b, 0x21, 0x40, 0xed, 0x8b, 0x21, 0x40, -0xf1, 0x8b, 0x21, 0x40, 0x7d, 0x8b, 0x21, 0x40, 0x05, 0x88, 0x21, 0x40, -0xa5, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xf5, 0x8b, 0x21, 0x40, -0xe9, 0xc1, 0x21, 0x40, 0xe9, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, -0xa5, 0x77, 0x21, 0x40, 0xcd, 0xc2, 0x21, 0x40, 0x03, 0xc3, 0x21, 0x40, -0x35, 0xc3, 0x21, 0x40, 0x4d, 0x8c, 0x21, 0x40, 0x3f, 0x7b, 0x21, 0x40, -0x99, 0x7e, 0x21, 0x40, 0xd5, 0x7e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40, 0x24, 0xa3, 0x20, 0x40, -0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40, 0x24, 0x83, 0x20, 0x40, -0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x8c, 0x01, 0x18, 0x40, 0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, -0x24, 0xab, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xef, 0x79, 0x21, 0x40, 0x8d, 0x7a, 0x21, 0x40, 0x9b, 0x7a, 0x21, 0x40, +0xa9, 0x7a, 0x21, 0x40, 0x51, 0x7b, 0x21, 0x40, 0x4f, 0x7f, 0x21, 0x40, +0xc9, 0x7f, 0x21, 0x40, 0x69, 0x80, 0x21, 0x40, 0x9d, 0x81, 0x21, 0x40, +0xa9, 0x81, 0x21, 0x40, 0x09, 0x82, 0x21, 0x40, 0x6d, 0x82, 0x21, 0x40, +0x99, 0x82, 0x21, 0x40, 0xbd, 0x82, 0x21, 0x40, 0xfd, 0x82, 0x21, 0x40, +0x25, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0x7d, 0x83, 0x21, 0x40, +0xa5, 0x83, 0x21, 0x40, 0xb5, 0x83, 0x21, 0x40, 0xfd, 0x83, 0x21, 0x40, +0x3b, 0x84, 0x21, 0x40, 0x91, 0x84, 0x21, 0x40, 0xf1, 0x84, 0x21, 0x40, +0xfb, 0x84, 0x21, 0x40, 0xff, 0x84, 0x21, 0x40, 0x6d, 0x85, 0x21, 0x40, +0xb9, 0x85, 0x21, 0x40, 0x11, 0x86, 0x21, 0x40, 0x4d, 0x86, 0x21, 0x40, +0xb1, 0x86, 0x21, 0x40, 0xe9, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, +0x31, 0x87, 0x21, 0x40, 0x41, 0x87, 0x21, 0x40, 0x55, 0x87, 0x21, 0x40, +0x7d, 0x87, 0x21, 0x40, 0x87, 0x87, 0x21, 0x40, 0x91, 0x87, 0x21, 0x40, +0xf5, 0x87, 0x21, 0x40, 0x25, 0x88, 0x21, 0x40, 0x31, 0x88, 0x21, 0x40, +0xa5, 0x88, 0x21, 0x40, 0xaf, 0x88, 0x21, 0x40, 0xb9, 0x88, 0x21, 0x40, +0xc3, 0x88, 0x21, 0x40, 0xcd, 0x88, 0x21, 0x40, 0xd7, 0x88, 0x21, 0x40, +0xe1, 0x88, 0x21, 0x40, 0xeb, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40, +0xe9, 0x8b, 0x21, 0x40, 0xff, 0x88, 0x21, 0x40, 0x09, 0x89, 0x21, 0x40, +0x13, 0x89, 0x21, 0x40, 0x1d, 0x89, 0x21, 0x40, 0x45, 0x89, 0x21, 0x40, +0x4f, 0x89, 0x21, 0x40, 0xb1, 0x89, 0x21, 0x40, 0xbb, 0x89, 0x21, 0x40, +0xc5, 0x89, 0x21, 0x40, 0xcf, 0x89, 0x21, 0x40, 0xd9, 0x89, 0x21, 0x40, +0xa5, 0x77, 0x21, 0x40, 0xe3, 0x89, 0x21, 0x40, 0x49, 0x8a, 0x21, 0x40, +0x95, 0x8a, 0x21, 0x40, 0xe1, 0x8a, 0x21, 0x40, 0xf1, 0x8a, 0x21, 0x40, +0xa5, 0x77, 0x21, 0x40, 0x3d, 0x8b, 0x21, 0x40, 0x41, 0x8b, 0x21, 0x40, +0x45, 0x8b, 0x21, 0x40, 0x9d, 0x8b, 0x21, 0x40, 0xc5, 0x8b, 0x21, 0x40, +0xd1, 0x8b, 0x21, 0x40, 0xd5, 0x8b, 0x21, 0x40, 0xd9, 0x8b, 0x21, 0x40, +0xdd, 0x8b, 0x21, 0x40, 0xe1, 0x8b, 0x21, 0x40, 0xe5, 0x8b, 0x21, 0x40, +0x0d, 0x88, 0x21, 0x40, 0x69, 0x88, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, +0xa5, 0x77, 0x21, 0x40, 0xf5, 0x8b, 0x21, 0x40, 0xe1, 0xc9, 0x21, 0x40, +0xe9, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, +0xdd, 0xca, 0x21, 0x40, 0x13, 0xcb, 0x21, 0x40, 0x45, 0xcb, 0x21, 0x40, +0x4d, 0x8c, 0x21, 0x40, 0x5b, 0x7b, 0x21, 0x40, 0xe5, 0x7e, 0x21, 0x40, +0x21, 0x7f, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, +0x58, 0x01, 0x18, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, +0x68, 0x01, 0x18, 0x40, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, +0x78, 0x01, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40, +0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, -0x00, 0x00, 0x00, 0x00, 0x11, 0xb2, 0x21, 0x40, 0x6d, 0xb3, 0x21, 0x40, -0x00, 0x00, 0x00, 0x00, 0x91, 0x73, 0x21, 0x40, 0x89, 0xaa, 0x21, 0x40, +0x00, 0x00, 0x00, 0x00, 0xa5, 0xb9, 0x21, 0x40, 0x01, 0xbb, 0x21, 0x40, +0x00, 0x00, 0x00, 0x00, 0x91, 0x73, 0x21, 0x40, 0x19, 0xb2, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x67, 0x92, 0x21, 0x40, 0x11, 0xb2, 0x21, 0x40, -0x39, 0x2f, 0xff, 0xff, 0xad, 0x20, 0xff, 0xff, 0x97, 0x20, 0xff, 0xff, -0xe9, 0xb0, 0x21, 0x40, 0xa0, 0x2d, 0x00, 0x80, 0xb4, 0x2d, 0x00, 0x80, -0xc8, 0x2d, 0x00, 0x80, 0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, -0x00, 0x30, 0x37, 0x2f, 0x32, 0x33, 0x2f, 0x30, -0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35, 0x36, 0x39, 0x00, 0x43, -0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, -0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43, 0x6f, 0x6d, 0x20, 0x43, -0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x00, -0x17, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x0c, 0x53, 0xff, 0xff, 0x27, 0xf0, 0x7d, 0xfd, -0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00, 0x01, 0x40, 0x64, 0x04, -0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, 0xe5, 0x3d, 0xff, 0xff, -0x49, 0x4f, 0xff, 0xff, 0x79, 0x24, 0xff, 0xff, 0x3d, 0x3b, 0xff, 0xff, -0x9d, 0x3b, 0xff, 0xff, 0xa1, 0x19, 0xff, 0xff, 0x19, 0x11, 0xff, 0xff, -0x4c, 0x53, 0xff, 0xff, 0x99, 0x3f, 0xff, 0xff, 0x91, 0x73, 0x21, 0x40, -0x51, 0x75, 0x21, 0x40, 0x51, 0x3f, 0xff, 0xff, 0x11, 0xa3, 0x21, 0x40, -0x29, 0x24, 0xff, 0xff, 0xe4, 0x52, 0xff, 0xff, 0x0c, 0x53, 0xff, 0xff, -0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, -0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, -0xb8, 0x60, 0x00, 0x00, 0x74, 0x6c, 0x00, 0x00, 0x00, 0x6e, 0x21, 0x40, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, -0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, -0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, -0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, -0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, -0xfd, 0x92, 0x21, 0x40, 0x9b, 0x92, 0x21, 0x40, 0xc1, 0x95, 0x21, 0x40, -0x21, 0x96, 0x21, 0x40, 0xe9, 0x96, 0x21, 0x40, 0xa7, 0x94, 0x21, 0x40, -0xc5, 0x97, 0x21, 0x40, 0x31, 0x98, 0x21, 0x40, 0x85, 0x94, 0x21, 0x40, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xa7, 0x99, 0x21, 0x40, 0xa5, 0xb9, 0x21, 0x40, +0xb1, 0x2f, 0xff, 0xff, 0xf1, 0x20, 0xff, 0xff, 0xdb, 0x20, 0xff, 0xff, +0x2d, 0xb8, 0x21, 0x40, 0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, +0x5c, 0x2e, 0x00, 0x80, 0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, +0x00, 0x30, 0x37, 0x2f, 0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, +0x30, 0x30, 0x31, 0x35, 0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, +0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, +0x31, 0x20, 0x33, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, +0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x00, 0x02, 0x10, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x78, 0x53, 0xff, 0xff, 0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, +0xda, 0x0e, 0x82, 0x00, 0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, +0xe4, 0x2c, 0x00, 0x80, 0x55, 0x3e, 0xff, 0xff, 0xb5, 0x4f, 0xff, 0xff, +0xc1, 0x24, 0xff, 0xff, 0xb5, 0x3b, 0xff, 0xff, 0x15, 0x3c, 0xff, 0xff, +0x05, 0x1a, 0xff, 0xff, 0x65, 0x11, 0xff, 0xff, 0xb8, 0x53, 0xff, 0xff, +0x0d, 0x40, 0xff, 0xff, 0x91, 0x73, 0x21, 0x40, 0x51, 0x75, 0x21, 0x40, +0xc5, 0x3f, 0xff, 0xff, 0x71, 0xaa, 0x21, 0x40, 0x71, 0x24, 0xff, 0xff, +0x50, 0x53, 0xff, 0xff, 0x78, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0xec, 0x68, 0x00, 0x00, +0x10, 0x5c, 0x00, 0x00, 0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, +0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, +0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, +0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, +0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, +0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3d, 0x9a, 0x21, 0x40, +0xdb, 0x99, 0x21, 0x40, 0xf5, 0x9c, 0x21, 0x40, 0x55, 0x9d, 0x21, 0x40, +0x1d, 0x9e, 0x21, 0x40, 0xdb, 0x9b, 0x21, 0x40, 0xf9, 0x9e, 0x21, 0x40, +0x65, 0x9f, 0x21, 0x40, 0xb9, 0x9b, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2051,7 +2063,6 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2084,92 +2095,93 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, -0xb5, 0xce, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xa9, 0xc3, 0x21, 0x40, -0x45, 0xc5, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xcc, 0x21, 0x40, -0x59, 0xcd, 0x21, 0x40, 0xc5, 0xcd, 0x21, 0x40, 0x09, 0x29, 0x09, 0xd1, +0xe9, 0xd6, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xcb, 0x21, 0x40, +0x55, 0xcd, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x25, 0xd5, 0x21, 0x40, +0x8d, 0xd5, 0x21, 0x40, 0xf9, 0xd5, 0x21, 0x40, 0x09, 0x29, 0x09, 0xd1, 0x20, 0x28, 0x07, 0xd2, 0x04, 0x48, 0x01, 0x78, 0x00, 0x29, 0x03, 0xd1, 0x01, 0x21, 0x01, 0x70, 0x02, 0x48, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x6e, 0x21, 0x40, 0x24, 0xab, 0x20, 0x40, 0x03, 0x49, 0x88, 0x42, 0x03, 0xd1, 0x00, 0x20, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x70, 0x70, 0x47, -0x24, 0xab, 0x20, 0x40, 0x00, 0x6e, 0x21, 0x40, -0x00, 0xb5, 0x00, 0x20, 0x0b, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, -0x2d, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x48, 0x61, 0x98, 0x60, 0x98, 0x63, -0x80, 0x32, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0x62, 0x05, 0x48, -0xc0, 0x46, 0x08, 0x60, 0x48, 0x60, 0x05, 0xf0, 0xc3, 0xf9, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xfe, 0x03, 0x00, 0x00, -0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c, 0x00, 0x23, 0x00, 0x93, -0xff, 0xf7, 0xda, 0xff, 0x68, 0x49, 0x0b, 0x23, 0x1b, 0x02, 0xcf, 0x18, -0x38, 0x68, 0x28, 0x40, 0x00, 0x22, 0xb8, 0x60, 0xfa, 0x60, 0x7a, 0x68, -0x22, 0x40, 0x3a, 0x61, 0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, -0x01, 0xd2, 0x80, 0x0a, 0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, -0x01, 0x20, 0xb9, 0x68, 0x49, 0x09, 0x03, 0xd2, 0x39, 0x69, 0x49, 0x09, -0x00, 0xd2, 0x00, 0x20, 0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xf8, 0xfd, -0xb8, 0x68, 0x00, 0x28, 0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, -0x54, 0x4a, 0x01, 0x23, 0x18, 0x43, 0xb8, 0x60, 0x00, 0x20, 0xd5, 0x1d, -0x79, 0x35, 0x03, 0x95, 0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xba, 0x68, -0x22, 0x40, 0x39, 0xd0, 0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, -0x9b, 0x5c, 0x1e, 0x1c, 0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, -0x5b, 0x78, 0x83, 0x42, 0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, -0x03, 0x9d, 0xad, 0x6a, 0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, -0xab, 0x62, 0x53, 0x68, 0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, -0x86, 0x42, 0x0a, 0xd1, 0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, -0x9b, 0x00, 0x3c, 0x4e, 0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, -0x5d, 0x61, 0x53, 0x78, 0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, -0x5d, 0x1c, 0x01, 0x95, 0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, -0x9b, 0x01, 0xeb, 0x18, 0x9a, 0x60, 0xfa, 0x68, 0x01, 0x32, 0xfa, 0x60, -0x64, 0x00, 0x01, 0x31, 0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, -0xb8, 0xd3, 0x00, 0x20, 0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, -0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0x48, 0x61, 0x01, 0x9b, 0x99, 0x00, -0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0x88, 0x60, 0x00, 0x9b, -0x00, 0x2b, 0x0c, 0xd1, 0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, -0xc9, 0x18, 0x8b, 0x69, 0xc0, 0x46, 0x4b, 0x61, 0x01, 0x30, 0x0b, 0x28, -0xf4, 0xd3, 0x08, 0xe0, 0x07, 0xe0, 0x03, 0x9d, 0xa8, 0x6a, 0x30, 0x28, -0x03, 0xd2, 0x30, 0x20, 0x03, 0x9d, 0xc0, 0x46, 0xa8, 0x62, 0x19, 0x4a, -0x38, 0x69, 0x00, 0x28, 0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, -0x38, 0x61, 0x00, 0x20, 0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x3b, 0x69, +0x24, 0xab, 0x20, 0x40, 0x00, 0x6e, 0x21, 0x40, 0x00, 0xb5, 0x00, 0x20, +0x0b, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23, 0x9b, 0x01, +0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32, 0xc8, 0x60, +0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x05, 0x48, 0xc0, 0x46, 0x48, 0x60, +0x88, 0x60, 0x05, 0xf0, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, +0x0c, 0x1c, 0x05, 0x1c, 0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xda, 0xff, +0x68, 0x49, 0x0b, 0x23, 0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40, +0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61, +0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a, +0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68, +0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20, +0x00, 0x06, 0x00, 0x0e, 0x04, 0xf0, 0xc8, 0xf9, 0xf8, 0x68, 0x00, 0x28, +0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23, +0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95, +0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0, +0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c, +0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42, +0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a, +0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68, +0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1, +0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e, +0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78, +0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95, +0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18, +0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31, +0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20, +0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, +0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23, +0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1, +0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69, +0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0, +0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, +0x03, 0xd2, 0x30, 0x20, 0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, +0x78, 0x69, 0x00, 0x28, 0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, +0x78, 0x61, 0x00, 0x20, 0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0, 0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78, 0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, -0x9b, 0x00, 0x9e, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x9d, 0x63, +0x9b, 0x00, 0x9e, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00, 0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3, 0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, -0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0x88, 0x63, 0x04, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0xb0, 0x52, 0xff, 0xff, -0x80, 0x00, 0x00, 0x80, 0x00, 0x47, 0x08, 0x47, -0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46, 0x34, 0xc0, 0x9f, 0xe5, -0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 0x2c, 0xc0, 0x9f, 0xe5, -0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 0x24, 0xc0, 0x9f, 0xe5, -0x1c, 0xff, 0x2f, 0xe1, 0xc0, 0x46, 0xff, 0xb4, 0x75, 0x46, 0x20, 0xb4, -0x01, 0x21, 0x08, 0x43, 0x01, 0xa4, 0xa6, 0x46, 0x00, 0x47, 0xc0, 0x46, -0x20, 0xbc, 0xae, 0x46, 0xff, 0xbc, 0xf7, 0x46, 0xb8, 0x51, 0xff, 0xff, -0x08, 0x51, 0xff, 0xff, 0xd7, 0xb7, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20, -0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01, -0xf8, 0x18, 0x05, 0x72, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20, -0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0, 0x19, 0x7b, 0x00, 0x29, -0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x1e, 0x1c, -0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20, 0x70, 0x60, 0x10, 0x4a, -0x10, 0x49, 0xff, 0xf7, 0xb5, 0xff, 0x00, 0x28, 0x07, 0xd0, 0x35, 0x73, -0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x20, 0x61, 0x00, 0xf0, -0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x18, 0x73, 0x04, 0x23, -0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61, 0xf5, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, -0xa8, 0x04, 0x00, 0x80, 0xa0, 0x54, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, -0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48, 0x40, 0x6e, 0x0c, 0x1a, -0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42, 0x06, 0xd8, 0x14, 0x4a, -0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 0xfa, 0x6b, 0x11, 0xe0, -0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, -0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x70, 0x68, -0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0xfa, 0x6b, -0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x74, 0xff, 0xf8, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, -0xa8, 0x04, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x37, 0x02, -0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68, 0xc0, 0x19, 0x20, 0x30, -0x29, 0x4a, 0xff, 0xf7, 0x55, 0xff, 0x01, 0x20, 0xc0, 0x02, 0x28, 0x49, -0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c, 0x26, 0x4d, 0x00, 0x24, -0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29, 0x31, 0xd1, 0x31, 0x68, -0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73, 0xf0, 0xbc, 0x08, 0xbc, +0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1c, 0x53, 0xff, 0xff, +0x00, 0x01, 0x00, 0x80, 0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, +0x78, 0x47, 0xc0, 0x46, 0x34, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, +0x78, 0x47, 0xc0, 0x46, 0x2c, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, +0x78, 0x47, 0xc0, 0x46, 0x24, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, +0xc0, 0x46, 0xff, 0xb4, 0x75, 0x46, 0x20, 0xb4, 0x01, 0x21, 0x08, 0x43, +0x01, 0xa4, 0xa6, 0x46, 0x00, 0x47, 0xc0, 0x46, 0x20, 0xbc, 0xae, 0x46, +0xff, 0xbc, 0xf7, 0x46, 0x24, 0x52, 0xff, 0xff, 0x74, 0x51, 0xff, 0xff, +0x51, 0xc0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20, 0x1a, 0x49, 0x01, 0x25, +0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01, 0xf8, 0x18, 0x05, 0x73, +0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20, 0x7a, 0x6e, 0x17, 0x4b, +0x8a, 0x42, 0x1d, 0xd0, 0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, +0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, +0xb0, 0x60, 0x10, 0x20, 0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, +0xb5, 0xff, 0x00, 0x28, 0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, +0x18, 0x43, 0xb8, 0x61, 0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, +0xb8, 0x61, 0x20, 0x61, 0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, +0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, +0x0c, 0x55, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, +0x39, 0x6c, 0x15, 0x48, 0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, +0x14, 0x4d, 0xa1, 0x42, 0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, +0xb9, 0x6b, 0x09, 0x18, 0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, +0x22, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, +0x2b, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, +0x02, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, +0xff, 0xf7, 0x74, 0xff, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, +0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, +0xb8, 0x68, 0x79, 0x68, 0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, +0x55, 0xff, 0x01, 0x20, 0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, +0xb9, 0x68, 0x38, 0x1c, 0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, +0x79, 0x37, 0x00, 0x29, 0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, +0x03, 0xd2, 0x04, 0x73, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff, 0x22, 0xe0, 0x09, 0x01, @@ -2178,85 +2190,85 @@ 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61, 0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60, 0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x17, 0xf9, 0x30, 0x68, -0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0, 0x02, 0x23, 0xb8, 0x6b, -0x18, 0x43, 0xb8, 0x63, 0xc4, 0xe7, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, -0x25, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0, -0xe8, 0x0d, 0x00, 0x80, 0x64, 0x01, 0x00, 0x80, 0xa0, 0x54, 0xff, 0xff, -0x85, 0x74, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49, -0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30, -0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0, -0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0, -0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, -0x81, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa8, 0x04, 0x00, 0x80, -0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88, -0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0, 0xf7, 0xf8, 0x17, 0xe0, -0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c, 0xff, 0xf7, 0xbd, 0xfe, -0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09, 0x0c, 0xd3, 0x69, 0x46, -0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46, 0x00, 0x21, 0x00, 0xf0, -0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, -0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x01, 0x00, 0x80, -0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b, 0xdd, 0x1d, 0xff, 0x35, -0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0, 0x00, 0x27, 0x00, 0xe0, -0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00, 0xdb, 0x19, 0x5b, 0x01, -0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01, 0xc7, 0x1d, 0x09, 0x37, -0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46, 0xe6, 0x50, 0x01, 0x30, -0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0, 0x00, 0x22, 0xbb, 0x08, -0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c, 0x9b, 0x00, 0xcb, 0x58, -0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30, 0x01, 0x32, 0x83, 0x42, -0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48, 0x02, 0x6d, 0x80, 0x6e, -0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a, 0xcb, 0x6c, 0x9a, 0x1a, -0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8, 0x26, 0x48, 0x81, 0x6b, -0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0, 0xc3, 0x19, 0xca, 0x6c, -0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43, 0x00, 0x92, 0x0a, 0x1c, -0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c, 0x12, 0xe0, 0x16, 0x1a, -0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18, 0x19, 0x48, 0x82, 0x6c, -0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0xb8, 0x1b, 0x18, 0x4a, -0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48, 0x82, 0x6c, 0x41, 0x6c, +0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0, 0x02, 0x23, 0xf8, 0x6b, +0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, +0x91, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, +0xe4, 0x01, 0x00, 0x80, 0x0c, 0x55, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, +0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49, 0x00, 0x27, 0x08, 0x60, +0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x47, 0x70, 0xe0, 0x69, +0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0, 0xd7, 0xf8, 0xe0, 0x69, +0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0, 0x01, 0x20, 0xe0, 0x61, +0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x27, 0x73, +0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80, 0xe8, 0x0e, 0x00, 0x80, +0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88, 0x6d, 0x28, 0x03, 0xdb, +0x38, 0x1c, 0x00, 0xf0, 0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, +0x09, 0x58, 0x38, 0x1c, 0xff, 0xf7, 0xbd, 0xfe, 0x00, 0x28, 0x0f, 0xd1, +0x39, 0x78, 0xc9, 0x09, 0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, +0xcf, 0xf8, 0x68, 0x46, 0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, +0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, +0x02, 0x1c, 0x41, 0x4b, 0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, +0x00, 0x2f, 0x01, 0xd0, 0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, +0x2f, 0x78, 0xfb, 0x00, 0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, +0x40, 0x78, 0x00, 0x01, 0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, +0xd6, 0x58, 0xc0, 0x46, 0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, +0x00, 0x29, 0x0f, 0xd0, 0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, +0x0b, 0xd9, 0x13, 0x1c, 0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, +0x01, 0x9b, 0x01, 0x30, 0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, +0x10, 0x27, 0x2b, 0x48, 0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, +0x03, 0xd8, 0x82, 0x1a, 0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, +0xba, 0x42, 0x05, 0xd8, 0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, +0x01, 0x20, 0x37, 0xe0, 0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, +0x22, 0x4a, 0x3a, 0x43, 0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, +0x92, 0x6c, 0x23, 0x1c, 0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, +0x49, 0x6c, 0x09, 0x18, 0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, +0xff, 0xf7, 0x50, 0xfe, 0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, +0xa3, 0x19, 0x14, 0x48, 0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x45, 0xfe, 0x01, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18, 0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61, 0x00, 0xe0, 0x88, 0x61, -0x0c, 0x48, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, 0x81, 0x63, 0x00, 0x20, -0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x72, 0x02, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xa8, 0x04, 0x00, 0x80, 0xfc, 0xba, 0x20, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0x00, 0x00, 0x19, 0x02, 0x68, 0x0e, 0x00, 0x80, 0x98, 0x19, 0x00, 0x80, +0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x00, 0x20, +0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73, 0x02, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80, 0xfc, 0xba, 0x20, 0x40, +0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, +0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80, 0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a, 0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a, 0x88, 0x66, 0x88, 0x6e, -0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, -0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42, -0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46, -0x08, 0x61, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, -0x3c, 0xef, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46, -0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80, -0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60, -0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60, -0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48, -0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, -0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x45, 0x20, 0x00, 0xab, -0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, -0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c, 0x00, 0xe0, 0x00, 0x20, -0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xa0, 0x82, 0x20, 0x40, -0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a, 0xc0, 0x46, 0x11, 0x81, -0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20, 0x40, 0x02, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xf5, 0xfe, 0x01, 0x20, -0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, -0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, -0x03, 0x49, 0xc0, 0x46, 0x08, 0x70, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, -0x00, 0x20, 0x70, 0x47, 0xa8, 0x0e, 0x00, 0x80, 0x00, 0x20, 0x04, 0x49, -0xc0, 0x46, 0x08, 0x70, 0xff, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x01, 0x31, -0x91, 0x60, 0x70, 0x47, 0xa8, 0x0e, 0x00, 0x80, 0x02, 0x20, 0xa1, 0x21, -0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x40, 0x02, -0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x88, -0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03, 0x48, 0x61, 0x02, 0x49, -0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x70, 0x47, 0x68, 0x1a, 0x00, 0x80, -0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b, 0x69, 0x46, 0xff, 0xf7, -0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, -0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40, 0x80, 0xb5, 0x85, 0xb0, -0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x5b, 0xff, 0xf8, 0x88, -0x04, 0xa9, 0x04, 0xf0, 0xef, 0xfd, 0x01, 0xab, 0x58, 0x80, 0x01, 0xa8, +0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, +0x7c, 0x29, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x06, 0x49, 0x4a, 0x6e, +0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42, 0x00, 0xd8, 0x80, 0x1a, +0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x61, 0x70, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, +0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46, 0x8a, 0x80, 0x00, 0x22, +0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80, 0xca, 0x80, 0x8a, 0x60, +0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60, 0x00, 0x22, 0x82, 0x80, +0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60, 0xc2, 0x60, 0x70, 0x47, +0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48, 0x41, 0x6b, 0x01, 0x31, +0x41, 0x63, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, +0xc0, 0x46, 0x00, 0x90, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, +0xdf, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, +0x01, 0xd1, 0x38, 0x1c, 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, +0xc1, 0x88, 0x09, 0x4a, 0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, +0xbd, 0xff, 0x01, 0x20, 0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, +0x00, 0x21, 0xff, 0xf7, 0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, +0xc3, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, +0x08, 0x71, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, +0x28, 0x0f, 0x00, 0x80, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, +0xff, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, +0x28, 0x0f, 0x00, 0x80, 0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, +0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, +0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, +0xa1, 0x21, 0x49, 0x03, 0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, +0x00, 0x20, 0x70, 0x47, 0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, +0x08, 0x49, 0x0f, 0x6b, 0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, +0xc0, 0x0e, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, +0xa9, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x80, 0x00, 0x14, 0x40, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, +0x38, 0x1c, 0xff, 0xf7, 0x5b, 0xff, 0xf8, 0x88, +0x04, 0xa9, 0x05, 0xf0, 0xf7, 0xf9, 0x01, 0xab, 0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8, 0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b, 0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68, 0xc0, 0x46, 0x03, 0x90, @@ -2266,52 +2278,54 @@ 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b, 0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22, 0x00, 0xab, 0x5a, 0x80, -0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70, -0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68, -0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31, -0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, -0x10, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, -0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48, -0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xd6, 0xfc, 0x00, 0x28, -0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xd1, 0xfc, -0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21, -0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x15, 0x79, 0x21, 0x40, -0x59, 0xcd, 0x21, 0x40, 0xf1, 0xcc, 0x21, 0x40, 0x00, 0xb5, 0xc0, 0x88, -0x04, 0xf0, 0x54, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, -0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, -0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, -0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, -0x04, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7, 0xb5, 0xfe, 0x1b, 0x48, -0xff, 0xf7, 0x96, 0xfc, 0x07, 0x1c, 0x00, 0x21, 0x20, 0x1c, 0x03, 0xf0, -0x4f, 0xff, 0x00, 0x28, 0x1c, 0xd0, 0x20, 0x1c, 0x04, 0xa9, 0x03, 0xf0, -0x2d, 0xfe, 0x04, 0x98, 0x04, 0x28, 0x05, 0xd9, 0x04, 0x98, 0x80, 0x08, +0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70, 0x00, 0x24, 0xdc, 0x80, +0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68, 0xc0, 0x46, 0x03, 0x90, +0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31, 0xff, 0xf7, 0x4c, 0xfe, +0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, +0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, +0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48, 0x00, 0x2a, 0x05, 0xd1, +0x0d, 0x49, 0xff, 0xf7, 0xd6, 0xfc, 0x00, 0x28, 0x0c, 0xda, 0x05, 0xe0, +0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xd1, 0xfc, 0x00, 0x28, 0x05, 0xda, +0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x22, 0xfe, +0x00, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xff, 0xff, 0x00, 0x00, 0x15, 0x79, 0x21, 0x40, 0x8d, 0xd5, 0x21, 0x40, +0x25, 0xd5, 0x21, 0x40, 0x00, 0xb5, 0xc0, 0x88, 0x05, 0xf0, 0x5c, 0xf9, +0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, +0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, +0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, +0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0x04, 0x1c, 0x08, 0x1c, +0x69, 0x46, 0xff, 0xf7, 0xb5, 0xfe, 0x1c, 0x48, 0xff, 0xf7, 0x96, 0xfc, +0x07, 0x1c, 0x1b, 0x4a, 0x00, 0x21, 0x20, 0x1c, 0xff, 0xf7, 0x92, 0xfc, +0x00, 0x28, 0x1d, 0xd0, 0x04, 0xa9, 0x18, 0x4a, 0x20, 0x1c, 0xff, 0xf7, +0x8b, 0xfc, 0x04, 0x98, 0x04, 0x28, 0x05, 0xd9, 0x04, 0x98, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x00, 0xe0, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 0x06, 0xa8, 0x00, 0x78, 0xc0, 0x46, 0xd8, 0x80, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46, 0x03, 0x90, 0x04, 0x33, -0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, -0x38, 0x1c, 0xff, 0xf7, 0x6c, 0xfc, 0x68, 0x46, 0x29, 0x1c, 0xff, 0xf7, -0xc3, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c, -0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, -0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xb2, 0xff, 0x08, 0xbc, 0x18, 0x47, -0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, -0x18, 0x47, 0xf3, 0xb5, 0xc6, 0xb0, 0x0f, 0x1c, 0x69, 0x46, 0x38, 0x1c, -0xff, 0xf7, 0x5e, 0xfe, 0x1c, 0x48, 0xff, 0xf7, 0x3f, 0xfc, 0xba, 0x68, -0x04, 0x1c, 0xfc, 0x2a, 0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, -0x04, 0x90, 0xf9, 0x1d, 0x09, 0x31, 0x05, 0xab, 0x00, 0x20, 0x7e, 0x78, -0x00, 0x2e, 0x0d, 0xdd, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, -0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, -0x00, 0x0c, 0x7e, 0x78, 0x86, 0x42, 0xf1, 0xdc, 0x46, 0x98, 0x04, 0xa9, -0x2b, 0x1c, 0xff, 0xf7, 0x2d, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x00, 0xa8, -0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, -0x20, 0x1c, 0xff, 0xf7, 0x12, 0xfc, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, -0x69, 0xfd, 0x01, 0x20, 0x48, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, -0x35, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, +0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, +0x38, 0x1c, 0xff, 0xf7, 0x6a, 0xfc, 0x68, 0x46, 0x29, 0x1c, 0xff, 0xf7, +0xc1, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x24, 0x02, 0xff, 0xff, 0xcd, 0xc0, 0x21, 0x40, 0x29, 0xbf, 0x21, 0x40, +0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, +0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, +0xff, 0xf7, 0xac, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, +0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, +0xc6, 0xb0, 0x0f, 0x1c, 0x69, 0x46, 0x38, 0x1c, +0xff, 0xf7, 0x58, 0xfe, 0x20, 0x48, 0xff, 0xf7, 0x39, 0xfc, 0x04, 0x1c, +0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a, 0x23, 0xd8, +0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, +0xc0, 0x46, 0x04, 0x90, 0x05, 0xa9, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, +0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd, 0x40, 0xcb, 0x40, 0xc1, 0x40, 0xcb, +0x40, 0xc1, 0x40, 0xcb, 0x40, 0xc1, 0x40, 0xcb, 0x40, 0xc1, 0x01, 0x30, +0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78, 0x86, 0x42, 0xf1, 0xdc, 0x46, 0x98, +0x04, 0xa9, 0x2b, 0x1c, 0xff, 0xf7, 0x20, 0xfc, 0x00, 0x28, 0x05, 0xd0, +0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, +0x07, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x05, 0xfc, 0x68, 0x46, 0x00, 0x21, +0xff, 0xf7, 0x5c, 0xfd, 0x01, 0x20, 0x48, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, +0x00, 0xb5, 0xff, 0xf7, 0x27, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d, 0x68, 0x68, 0x01, 0x30, -0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7, 0x0f, 0xfe, 0x10, 0x2c, +0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7, 0x01, 0xfe, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0, 0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68, 0x00, 0x2a, 0x15, 0xd9, @@ -2322,1121 +2336,1275 @@ 0x02, 0x94, 0x69, 0x68, 0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a, 0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42, 0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, -0x11, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x1c, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x22, 0x48, 0x00, 0x68, 0x01, 0x21, +0x03, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x9c, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3, 0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, -0x00, 0xd2, 0x02, 0x22, 0x11, 0x43, 0x1d, 0x4a, 0x20, 0x24, 0xd3, 0x68, -0x01, 0x2b, 0x2c, 0xd1, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, -0x20, 0x1c, 0x1b, 0x23, 0xdb, 0x01, 0xd1, 0x18, 0x09, 0x8b, 0x09, 0x0b, -0x00, 0xd2, 0x04, 0x27, 0x38, 0x43, 0xd1, 0x6f, 0x09, 0x0a, 0x06, 0xd2, -0xd1, 0x1d, 0x79, 0x31, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23, -0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x78, 0x03, 0x29, -0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a, -0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07, -0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c, -0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x10, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, -0xf0, 0xb5, 0x33, 0x4d, 0x28, 0x1c, 0x05, 0xf0, 0x6b, 0xf8, 0x32, 0x49, -0xe3, 0x23, 0x1b, 0x01, 0xcf, 0x18, 0xba, 0x78, 0x30, 0x4e, 0x00, 0x20, -0xcc, 0x1d, 0x79, 0x34, 0x05, 0x2a, 0x53, 0xd2, 0x01, 0xa3, 0x9b, 0x5c, -0x5b, 0x00, 0x9f, 0x44, 0x02, 0x0e, 0x23, 0x3c, 0x3e, 0x00, 0x01, 0x21, -0xb9, 0x70, 0xb0, 0x60, 0xff, 0xf7, 0x98, 0xff, 0x04, 0x23, 0x98, 0x43, -0x00, 0xf0, 0x62, 0xf8, 0x14, 0x22, 0x28, 0x1c, 0x0e, 0xe0, 0xff, 0xf7, -0x8f, 0xff, 0xc0, 0x08, 0x06, 0xd3, 0xb1, 0x68, 0x48, 0x1c, 0xb0, 0x60, -0x0a, 0x29, 0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x70, -0x02, 0x22, 0x28, 0x1c, 0x00, 0x21, 0x05, 0xf0, 0x07, 0xf8, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0xc8, 0x6f, 0x18, 0x43, 0xc8, 0x67, -0x18, 0x4e, 0xc0, 0x46, 0x30, 0x60, 0x03, 0x20, 0xb8, 0x70, 0x28, 0x1c, -0x16, 0x4a, 0x00, 0x21, 0x04, 0xf0, 0xf6, 0xff, 0x11, 0x48, 0x04, 0x23, -0xc1, 0x6f, 0x99, 0x43, 0xc1, 0x67, 0x31, 0x60, 0x20, 0x68, 0x18, 0x43, -0x20, 0x60, 0x70, 0x60, 0xe3, 0xe7, 0x05, 0x21, 0xb9, 0x70, 0x51, 0x21, -0x89, 0x03, 0x08, 0x62, 0x04, 0x23, 0x20, 0x68, 0x98, 0x43, 0x20, 0x60, -0x09, 0x4e, 0xc0, 0x46, 0x70, 0x60, 0xff, 0xf7, 0x55, 0xff, 0x04, 0x23, -0x18, 0x43, 0x00, 0xf0, 0x1f, 0xf8, 0xd0, 0xe7, -0x06, 0x20, 0xb8, 0x70, 0xcd, 0xe7, 0x00, 0x00, 0x79, 0x7c, 0x21, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x1c, 0x03, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, -0x88, 0x13, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, -0x88, 0x70, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x04, 0xf0, 0xc0, 0xff, -0x08, 0xbc, 0x18, 0x47, 0x18, 0x1c, 0x00, 0x80, 0x79, 0x7c, 0x21, 0x40, -0x90, 0xb5, 0x07, 0x1c, 0x30, 0x48, 0x00, 0x68, 0x01, 0x1c, 0x7a, 0x08, -0x02, 0xd3, 0x10, 0x23, 0x98, 0x43, 0x01, 0xe0, 0x10, 0x23, 0x18, 0x43, -0xba, 0x08, 0x03, 0xd3, 0x01, 0x23, 0x1b, 0x03, 0x98, 0x43, 0x02, 0xe0, -0x01, 0x23, 0x1b, 0x03, 0x18, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x01, 0x21, -0x09, 0x05, 0x08, 0x60, 0x25, 0x4c, 0xe0, 0x68, 0x01, 0x28, 0x1e, 0xd1, -0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x00, 0x8b, 0xf9, 0x08, 0x04, 0xd3, -0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0, 0x01, 0x21, -0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20, 0x02, 0xf0, 0x20, 0xfe, -0x08, 0x21, 0x39, 0x40, 0x1a, 0x48, 0x03, 0xd0, 0x80, 0x23, 0xe1, 0x6f, -0x99, 0x43, 0x02, 0xe0, 0x80, 0x23, 0xe1, 0x6f, 0x19, 0x43, 0xe1, 0x67, -0x01, 0x60, 0x16, 0x48, 0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, +0x00, 0xd2, 0x02, 0x22, 0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, +0x01, 0x2b, 0x2e, 0xd1, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, +0x20, 0x1c, 0x1b, 0x23, 0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, +0x00, 0xd2, 0x04, 0x27, 0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, +0x07, 0xd2, 0xd1, 0x1d, 0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, +0x01, 0xd3, 0x08, 0x23, 0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, +0x89, 0x79, 0x03, 0x29, 0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, +0x0b, 0x49, 0x09, 0x6a, 0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, +0x10, 0x43, 0x89, 0x07, 0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, +0x70, 0x47, 0x40, 0x0c, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, +0xec, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, +0xc0, 0x00, 0x18, 0x40, 0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x05, 0xf0, +0x75, 0xfc, 0x39, 0x48, 0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, +0x37, 0x4e, 0xc5, 0x1d, 0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, +0x5b, 0x5c, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, +0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20, 0xb8, 0x71, 0x00, 0x20, +0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23, 0x98, 0x43, 0x00, 0xf0, +0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff, 0xc0, 0x08, 0x06, 0xd3, +0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28, 0x03, 0xd9, 0x04, 0x20, +0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22, 0x20, 0x1c, 0x2b, 0xe0, +0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, +0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a, 0x00, 0x21, 0x05, 0xf0, +0x07, 0xfc, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, +0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68, 0x04, 0x23, 0x0a, 0x68, +0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, +0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43, 0x00, 0xf0, 0x34, 0xf8, +0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x05, 0xf0, 0xe5, 0xfb, 0xe5, 0xe7, +0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43, 0x00, 0xf0, 0x28, 0xf8, +0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23, 0x0a, 0x68, 0x9a, 0x43, +0x0a, 0x60, 0xff, 0xf7, 0xe1, 0xfa, 0xd5, 0xe7, 0x06, 0x20, 0xb8, 0x71, +0xd2, 0xe7, 0x00, 0x00, 0x99, 0x7c, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, +0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, +0x00, 0xb5, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, +0x01, 0x22, 0x00, 0x21, 0x05, 0xf0, 0xbc, 0xfb, 0x08, 0xbc, 0x18, 0x47, +0x98, 0x1c, 0x00, 0x80, 0x99, 0x7c, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, +0x31, 0x48, 0x00, 0x68, 0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, +0x99, 0x43, 0x01, 0xe0, 0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, +0x01, 0x2a, 0x05, 0xd1, 0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, +0x9b, 0x02, 0x19, 0x43, 0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, +0x01, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, +0xe0, 0x18, 0x80, 0x8b, 0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, +0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, +0x02, 0xd0, 0x00, 0x20, 0x03, 0xf0, 0xca, 0xf9, 0x38, 0x09, 0x07, 0xd3, +0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, +0x00, 0x68, 0x00, 0xe0, 0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, +0x01, 0x60, 0x15, 0x48, 0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08, 0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, -0x10, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x62, +0x10, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29, 0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, -0x04, 0x33, 0x18, 0x40, 0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x90, 0xff, +0x04, 0x33, 0x18, 0x40, 0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x40, -0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7, 0xc1, 0xfe, 0x80, 0x09, -0x12, 0xd2, 0x0b, 0x48, 0x41, 0x78, 0x00, 0x29, 0x0e, 0xd1, 0x01, 0x21, -0x41, 0x70, 0x00, 0x27, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x03, 0xf0, -0x03, 0xf8, 0x07, 0x20, 0x02, 0xf0, 0xd2, 0xff, 0x38, 0x1c, 0xff, 0xf7, -0x5b, 0xfa, 0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x18, 0x1c, 0x00, 0x80, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, -0x69, 0x46, 0xff, 0xf7, 0x69, 0xfc, 0xff, 0xf7, 0x9d, 0xfe, 0x01, 0xab, -0x58, 0x80, 0x08, 0x48, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, -0x00, 0x6a, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, -0x99, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, -0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x49, 0xfc, 0xf8, 0x88, -0xff, 0xf7, 0x4a, 0xff, 0xff, 0xf7, 0x7a, 0xfe, 0x01, 0xab, 0x58, 0x80, -0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x7e, 0xfb, 0x01, 0x20, 0x04, 0xb0, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, -0x69, 0x46, 0xff, 0xf7, 0x33, 0xfc, 0x01, 0x24, 0x63, 0x02, 0x9f, 0x42, -0x0a, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, -0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x16, 0xe0, -0x0e, 0x48, 0xff, 0xf7, 0x05, 0xfa, 0x05, 0x1c, 0x38, 0x1c, 0x04, 0xa9, -0x03, 0xf0, 0xa2, 0xfb, 0x0b, 0x49, 0x28, 0x1c, -0xff, 0xf7, 0xfd, 0xf9, 0x10, 0x20, 0x00, 0xab, 0x58, 0x70, 0x04, 0x98, -0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, -0x06, 0xa9, 0xff, 0xf7, 0x4b, 0xfb, 0x20, 0x1c, 0x46, 0xb0, 0xb0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, +0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, +0x80, 0xb5, 0xff, 0xf7, 0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, +0xe3, 0x23, 0x1b, 0x01, 0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, +0x01, 0x22, 0x4a, 0x71, 0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, +0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x08, 0x48, +0x06, 0xe0, 0x02, 0x20, 0x03, 0xf0, 0x7e, 0xfb, 0x07, 0x20, 0x03, 0xf0, +0x4d, 0xfb, 0x38, 0x1c, 0xff, 0xf7, 0x34, 0xfa, 0xf5, 0xe7, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf4, 0x01, 0xff, 0xff, +0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 0x43, 0xfc, 0xff, 0xf7, +0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48, 0x00, 0x68, 0xc0, 0x46, +0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, +0x00, 0x21, 0xff, 0xf7, 0x73, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, +0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, +0x23, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff, 0xff, 0xf7, 0x62, 0xfe, +0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x58, 0xfb, +0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, +0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7, 0x0d, 0xfc, 0x01, 0x24, +0x16, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, +0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, +0x00, 0x21, 0x17, 0xe0, 0x10, 0x48, 0xff, 0xf7, 0xdf, 0xf9, 0x05, 0x1c, +0x0f, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0xdb, 0xf9, 0x0e, 0x49, +0x28, 0x1c, 0xff, 0xf7, 0xd6, 0xf9, 0x10, 0x20, 0x00, 0xab, 0x58, 0x70, +0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46, 0x03, 0x90, +0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x24, 0xfb, 0x20, 0x1c, 0x46, 0xb0, +0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, +0x24, 0x02, 0xff, 0xff, 0x29, 0xbf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, -0xfb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x02, 0xd1, +0xcf, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x02, 0xd1, 0x43, 0x01, 0x9c, 0x42, 0x09, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, -0x2c, 0xe0, 0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, +0x27, 0xe0, 0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28, 0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, -0x09, 0x0c, 0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0d, 0x48, 0xff, 0xf7, -0xaf, 0xf9, 0x06, 0x1c, 0x20, 0x1c, 0x04, 0xa9, 0x03, 0xf0, 0x76, 0xfb, -0x0a, 0x49, 0x30, 0x1c, 0xff, 0xf7, 0xa7, 0xf9, 0x38, 0x68, 0xc0, 0x46, -0x00, 0x90, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 0x68, 0x46, 0x00, 0x21, -0xff, 0xf7, 0xf8, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, -0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27, 0xe6, 0x88, 0xa2, 0x68, -0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x2e, 0x01, 0xd0, -0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0, 0x04, 0x2e, 0x00, 0xd1, -0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e, 0x66, 0xd2, 0x02, 0xa3, -0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, 0x03, 0x06, 0x08, 0x0c, -0x10, 0x00, 0x85, 0x83, 0x00, 0x23, 0x03, 0xe0, 0x85, 0x83, 0x05, 0xe0, -0x00, 0x23, 0x83, 0x83, 0xc3, 0x83, 0x06, 0xe0, 0x00, 0x23, 0x83, 0x83, -0xc5, 0x83, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33, 0x83, 0x83, 0xcb, 0x1d, -0x79, 0x33, 0x1e, 0x89, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x02, 0xdb, -0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22, 0x6d, 0x23, 0x5b, 0x01, -0xc9, 0x18, 0x09, 0x88, 0xff, 0x23, 0xe1, 0x33, 0x99, 0x43, 0x01, 0x23, -0x19, 0x43, 0x86, 0x8b, 0xff, 0x33, 0x9e, 0x42, 0x0d, 0xd1, 0xff, 0x20, -0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0x9b, 0x02, -0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21, 0x89, 0x02, 0x01, 0x43, -0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0xc0, 0x8b, 0x01, 0x28, 0x04, 0xd1, -0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0, 0x0c, 0xe0, 0x20, 0x23, -0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1, 0xc0, 0x8b, 0x01, 0x28, -0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43, 0x00, 0x2a, 0x05, 0xd0, -0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, -0x04, 0x20, 0x02, 0xf0, 0x8d, 0xfc, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, -0x02, 0xf0, 0x88, 0xfc, 0x00, 0x2f, 0x02, 0xd1, 0x00, 0x20, 0x12, 0xe0, -0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x2b, 0xfb, 0x00, 0xa8, -0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, -0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0x5e, 0xfa, -0x28, 0x1c, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80, -0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47, -0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28, 0x07, 0xd1, 0x37, 0x23, -0x9b, 0x01, 0xf8, 0x18, 0xc0, 0x89, 0x80, 0x21, 0x01, 0x43, 0x1b, 0x20, -0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x01, 0x21, -0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0, 0x4b, 0xfc, 0x01, 0x20, -0x07, 0x23, 0x5b, 0x02, 0xf9, 0x18, 0x88, 0x83, 0xc8, 0x83, 0x1b, 0x23, -0xdb, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x01, 0x23, 0x1b, 0x03, 0x98, 0x43, -0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0x38, 0xfc, -0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x37, 0x23, -0x9b, 0x01, 0xf8, 0x18, 0xc0, 0x89, 0x80, 0x23, 0x98, 0x43, 0x01, 0x1c, -0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, 0x00, 0x8b, -0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c, 0x10, 0x20, 0x02, 0xf0, -0x19, 0xfc, 0xff, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xf9, 0x18, 0x01, 0x30, -0x88, 0x83, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x41, 0x23, -0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02, 0x01, 0x43, 0x00, 0x20, -0x02, 0xf0, 0x06, 0xfc, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0xcf, 0x6a, -0x69, 0x46, 0xff, 0xf7, 0xa5, 0xfa, 0xb8, 0x05, 0x80, 0x0d, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xdd, 0xf9, 0x01, 0x20, -0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, -0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49, 0xc9, 0x6a, 0x1b, 0x23, -0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49, 0xc0, 0x46, 0xc8, 0x62, -0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x00, -0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a, 0x01, 0x2f, 0x01, 0xd1, -0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1, 0x3f, 0x03, 0x03, 0xe0, -0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02, 0x69, 0x46, 0xff, 0xf7, -0x71, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, -0xab, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20, 0x40, 0x03, 0x00, 0x21, -0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1, 0x02, 0x22, 0x04, 0xe0, -0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1, 0x01, 0x22, 0x02, 0x62, -0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, -0x07, 0x1c, 0x02, 0xf0, 0xb7, 0xfb, 0x69, 0x46, 0x04, 0x1c, 0x38, 0x1c, -0xff, 0xf7, 0x46, 0xfa, 0x01, 0xab, 0x5c, 0x80, 0x09, 0x4f, 0xf8, 0x6d, -0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x7c, 0xf9, -0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49, 0xc0, 0x46, 0x88, 0x62, +0x09, 0x0c, 0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0a, 0x48, 0xff, 0xf7, +0x83, 0xf9, 0x07, 0x1c, 0x09, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, +0x7f, 0xf9, 0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x7a, 0xf9, 0x68, 0x46, +0x00, 0x21, 0xff, 0xf7, 0xd1, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x51, 0xbf, 0x21, 0x40, +0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27, +0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0, +0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0, +0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e, +0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, +0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0, +0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0, +0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, +0xff, 0x23, 0x01, 0x33, 0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, +0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, +0x00, 0xe0, 0x01, 0x22, 0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, +0xff, 0x23, 0xe1, 0x33, 0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, +0xff, 0x33, 0x9e, 0x42, 0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, +0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, +0x20, 0xe0, 0x01, 0x21, 0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, +0x0a, 0xd1, 0x40, 0x88, 0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, +0x00, 0x2a, 0x13, 0xd0, 0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, +0x00, 0x2e, 0x0d, 0xd1, 0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, +0x81, 0x33, 0x19, 0x43, 0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, +0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x03, 0xf0, +0x2d, 0xf8, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0x03, 0xf0, 0x28, 0xf8, +0x00, 0x2f, 0x02, 0xd1, 0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, +0x20, 0x1c, 0xff, 0xf7, 0x03, 0xfb, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, +0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, +0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0x36, 0xfa, 0x28, 0x1c, 0x04, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, +0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62, +0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28, +0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21, +0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, +0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0, +0xeb, 0xff, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80, +0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, +0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20, +0x02, 0xf0, 0xd8, 0xff, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28, +0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23, +0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01, +0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c, +0x10, 0x20, 0x02, 0xf0, 0xb9, 0xff, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01, +0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, +0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02, +0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xa6, 0xff, 0x00, 0x20, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, +0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x7d, 0xfa, 0xb8, 0x05, +0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, +0xb5, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49, +0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49, +0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40, +0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, +0x0d, 0x49, 0x0f, 0x6a, 0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, +0x02, 0x2f, 0x01, 0xd1, 0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, +0x01, 0x27, 0xff, 0x02, 0x69, 0x46, 0xff, 0xf7, 0x49, 0xfa, 0x01, 0xab, +0x5f, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x83, 0xf9, 0x01, 0x20, +0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, +0xc2, 0x88, 0xa1, 0x20, 0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, +0x9a, 0x42, 0x01, 0xd1, 0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, +0x9a, 0x42, 0x02, 0xd1, 0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, +0x08, 0x1c, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, +0x57, 0xff, 0x69, 0x46, 0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x1e, 0xfa, +0x01, 0xab, 0x5c, 0x80, 0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, +0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x54, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, +0xc0, 0x0f, 0x05, 0x49, 0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, +0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, +0x68, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, +0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, +0x69, 0x46, 0xff, 0xf7, 0xf7, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab, +0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x2f, 0xf9, 0x01, 0x20, +0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, +0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47, +0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68, +0xff, 0xf7, 0xda, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49, +0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0, +0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, +0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, +0x03, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68, +0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0xcf, 0xfe, 0x00, 0x20, +0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0xae, 0xf9, 0x00, 0xa8, 0x00, 0x78, +0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, +0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xe1, 0xf8, 0x01, 0x20, +0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88, +0x69, 0x46, 0xff, 0xf7, 0x97, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x78, 0xff, +0x02, 0x20, 0x39, 0x1c, 0x03, 0xf0, 0x3c, 0xfe, 0x00, 0x28, 0x06, 0xd0, +0x02, 0x20, 0x39, 0x1c, 0x03, 0xf0, 0x8c, 0xfd, 0x01, 0xab, 0x58, 0x80, +0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c, +0xfe, 0xf7, 0x65, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xbc, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x10, 0x2a, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80, 0xc0, 0x88, 0x02, 0x49, -0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, -0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 0x1f, 0xfa, 0x06, 0x48, -0xc0, 0x68, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, -0x00, 0x21, 0xff, 0xf7, 0x57, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, -0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, -0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68, 0xff, 0xf7, 0x02, 0xfa, -0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49, 0x40, 0x18, 0x1b, 0x23, -0xdb, 0x01, 0xc0, 0x18, 0x00, 0x8b, 0x06, 0xe0, 0x00, 0xa8, 0x00, 0x78, -0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x2b, 0xf9, 0x01, 0x20, -0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68, 0x20, 0x2a, 0x04, 0xd2, -0x10, 0x1c, 0x02, 0xf0, 0x2f, 0xfb, 0x00, 0x20, 0x10, 0xe0, 0x69, 0x46, -0xff, 0xf7, 0xd6, 0xf9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, -0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, -0x04, 0x33, 0xff, 0xf7, 0x09, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, -0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7, -0xbf, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0xa0, 0xff, 0x02, 0x20, 0x39, 0x1c, -0x03, 0xf0, 0x5a, 0xfa, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x20, 0x39, 0x1c, -0x03, 0xf0, 0x94, 0xf9, 0x01, 0xab, 0x58, 0x80, 0x02, 0xe0, 0x45, 0x20, -0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c, 0xfe, 0xf7, 0x8d, 0xff, -0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xe4, 0xf8, 0x01, 0x20, 0x04, 0xb0, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, -0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0, 0xc7, 0x88, 0x69, 0x46, -0x84, 0x68, 0xff, 0xf7, 0x93, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x74, 0xff, -0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7, 0x71, 0xff, 0x00, 0x28, -0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c, 0x22, 0x1c, 0xfe, 0xf7, -0x6a, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, -0x28, 0x1c, 0xfe, 0xf7, 0x60, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, -0xb7, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x24, 0x02, 0xff, 0xff, 0xb9, 0xb8, 0x21, 0x40, 0x7b, 0xb7, 0x21, 0x40, -0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x7f, 0xf9, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4, 0xc2, 0x88, 0x19, 0x4b, -0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1, 0x18, 0x6b, 0x10, 0x23, -0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1, 0x18, 0x6b, 0x10, 0x23, -0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a, 0x1d, 0xd1, 0xc2, 0x68, -0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, -0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, -0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c, 0xc3, 0x40, 0xdb, 0x07, -0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37, 0x3b, 0x43, 0x0b, 0x61, -0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf1, 0xdb, 0x00, 0x20, -0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40, 0x90, 0xb4, 0xc2, 0x88, -0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43, 0x02, 0x04, 0x12, 0x0c, -0x0f, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0f, 0x4f, 0x65, 0x23, 0x5b, 0x01, -0xfb, 0x18, 0x9a, 0x83, 0x0a, 0x0c, 0x14, 0x02, -0x12, 0x12, 0x22, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0xda, 0x83, +0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0, +0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x6b, 0xf9, 0x10, 0x48, +0xfe, 0xf7, 0x4c, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7, +0x49, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c, +0x22, 0x1c, 0xfe, 0xf7, 0x42, 0xff, 0x02, 0xe0, +0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, +0x38, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x8f, 0xf8, 0x01, 0x20, +0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, +0xcd, 0xc0, 0x21, 0x40, 0xd9, 0xbf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, +0x00, 0xb5, 0xff, 0xf7, 0x57, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, +0x70, 0x47, 0x80, 0xb4, 0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, +0x00, 0x2a, 0x03, 0xd1, 0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, +0x01, 0x2a, 0x04, 0xd1, 0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, +0x1f, 0xe0, 0x02, 0x2a, 0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, +0x3b, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, +0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, +0x00, 0x20, 0x13, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, +0xc7, 0x1d, 0x19, 0x37, 0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, +0x00, 0x0c, 0x20, 0x28, 0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, +0x80, 0x00, 0x14, 0x40, 0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, +0x12, 0x0a, 0x10, 0x43, 0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, +0x02, 0x60, 0x0c, 0x4b, 0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02, +0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04, -0x09, 0x0c, 0x81, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x01, 0x80, -0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, -0xe8, 0x0d, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0, 0x13, 0x49, 0x0a, 0x68, -0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12, 0x13, 0x43, 0x4a, 0x68, -0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02, 0x12, 0x12, 0x13, 0x43, -0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, -0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c, 0xff, 0xf7, 0xe4, 0xf8, -0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43, 0x02, 0x90, 0x68, 0x46, -0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, 0xc1, 0x88, 0x82, 0x68, -0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x0a, 0x49, -0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02, 0x00, 0x12, 0x18, 0x43, -0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04, 0x00, 0x0c, 0x02, 0x02, -0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x48, 0x61, 0x00, 0x20, -0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb5, 0x84, 0xb0, -0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x12, -0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c, 0x17, 0x02, 0x12, 0x12, -0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c, 0x1f, 0x02, 0x1b, 0x12, -0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23, 0x00, 0x93, 0x84, 0x88, -0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b, 0x5c, 0x70, 0x40, 0x88, -0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04, 0x38, 0x43, 0x02, 0x90, -0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xcb, 0xff, 0x01, 0x20, -0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, -0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a, 0x05, 0x21, 0x00, 0x91, -0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, -0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, -0x68, 0x46, 0xfe, 0xf7, 0xaf, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, -0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, -0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a, 0x05, 0x21, 0x00, 0x91, -0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, -0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, -0x68, 0x46, 0xfe, 0xf7, 0x8b, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, -0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, -0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7, 0x1c, 0xfe, 0x00, 0x20, -0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, -0x69, 0x46, 0xff, 0xf7, 0x2d, 0xf8, 0x06, 0x48, 0x00, 0x6b, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x65, 0xff, 0x01, 0x20, -0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0xb5, 0xff, 0xf7, 0x33, 0xf8, 0x08, 0xbc, -0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x2e, 0xf8, 0x08, 0xbc, 0x18, 0x47, -0x00, 0xb5, 0xff, 0xf7, 0x29, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, -0x01, 0x20, 0x14, 0x4f, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x71, -0x12, 0x48, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, -0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0xf9, 0x1d, 0xb9, 0x31, 0x08, 0x70, -0x0d, 0x4a, 0x01, 0x23, 0x1b, 0x04, 0x11, 0x68, 0x0b, 0x40, 0x12, 0x21, -0x00, 0x2b, 0x05, 0xd1, 0x13, 0x68, 0x1b, 0x0c, 0x08, 0xd1, 0x12, 0x68, -0x92, 0x0a, 0x05, 0xd3, 0x07, 0x4a, 0xc0, 0x46, 0xd1, 0x60, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x05, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0xf8, 0xe7, -0xe8, 0x0d, 0x00, 0x80, 0xa9, 0x9d, 0x21, 0x40, 0x00, 0x00, 0x10, 0x40, -0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x02, 0xf0, -0x83, 0xfb, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, -0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0x88, 0xfc, 0x00, 0x28, 0x0c, 0xd1, -0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xc8, 0xff, 0x06, 0x48, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x01, 0xff, 0x01, 0x20, +0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, +0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0, +0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12, +0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02, +0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, +0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c, +0xff, 0xf7, 0xc2, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43, +0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xf9, 0xff, 0x01, 0x20, +0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, +0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04, +0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02, +0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04, +0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c, +0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, +0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c, +0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c, +0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c, +0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23, +0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b, +0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04, +0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, +0xa9, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a, +0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, +0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, +0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, +0x8d, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, +0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, +0x0b, 0x49, 0x0a, 0x6a, 0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, +0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, +0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, +0x69, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, +0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, +0x02, 0x49, 0xfe, 0xf7, 0xfa, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, +0x75, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, +0x0b, 0xf8, 0x06, 0x48, 0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, +0x00, 0x21, 0xfe, 0xf7, 0x43, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, +0x11, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x0c, 0xf8, +0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x07, 0xf8, 0x08, 0xbc, +0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xcc, 0xfd, +0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21, +0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c, +0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, +0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48, +0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x21, 0xa5, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, +0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20, +0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff, +0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20, +0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff, +0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x02, 0xf0, +0xf3, 0xfe, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, +0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xf8, 0xff, 0x00, 0x28, 0x0c, 0xd1, +0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x96, 0xff, 0x06, 0x48, 0x01, 0xab, +0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xcf, 0xfe, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, -0xb3, 0xff, 0x03, 0xf0, 0x71, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x09, 0x48, +0x81, 0xff, 0x04, 0xf0, 0x47, 0xfa, 0x01, 0xab, 0x58, 0x80, 0x09, 0x48, 0x81, 0x89, 0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04, 0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, -0xfe, 0xf7, 0xe0, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, -0xc8, 0x29, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xaf, 0xff, 0x08, 0xbc, -0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xaa, 0xff, 0x08, 0xbc, 0x18, 0x47, -0x00, 0xb5, 0xfe, 0xf7, 0xa5, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, -0xfe, 0xf7, 0xa0, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, -0x9b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x96, 0xff, -0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x91, 0xff, 0x08, 0xbc, -0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x8c, 0xff, 0x08, 0xbc, 0x18, 0x47, -0x00, 0xb5, 0xfe, 0xf7, 0x87, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, -0xfe, 0xf7, 0x82, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, -0x7d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x78, 0xff, -0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x73, 0xff, 0x08, 0xbc, -0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7, 0x54, 0xff, -0x69, 0x46, 0x08, 0xa8, 0x03, 0xf0, 0xba, 0xfe, 0x02, 0x20, 0x08, 0xab, -0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x89, 0xfe, 0x01, 0x20, -0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x5a, 0xff, -0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, -0x38, 0x1c, 0xfe, 0xf7, 0x39, 0xff, 0xf9, 0x88, 0x10, 0x48, 0x01, 0x24, -0x00, 0x29, 0x0e, 0xd0, 0x04, 0x73, 0x44, 0x73, 0xb9, 0x68, 0x09, 0x0c, -0x41, 0x82, 0xb9, 0x68, 0xc0, 0x46, 0x81, 0x82, 0xf9, 0x68, 0x09, 0x0c, -0xc1, 0x82, 0xf9, 0x68, 0xc0, 0x46, 0x01, 0x83, 0x02, 0xe0, 0x00, 0x21, -0x01, 0x73, 0x41, 0x73, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, -0x00, 0x21, 0xfe, 0xf7, 0x5b, 0xfe, 0x20, 0x1c, -0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, -0xff, 0xff, 0x00, 0x00, 0x00, 0xb5, 0xfe, 0xf7, 0x27, 0xff, 0x08, 0xbc, -0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x22, 0xff, 0x08, 0xbc, 0x18, 0x47, -0x00, 0xb5, 0xfe, 0xf7, 0x1d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, -0xfe, 0xf7, 0x18, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, -0x13, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, -0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf2, 0xfe, 0xf8, 0x88, 0x03, 0x24, -0xe4, 0x04, 0x04, 0x43, 0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, -0x0f, 0x4b, 0x9c, 0x42, 0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, -0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x20, 0xfe, 0x01, 0x20, 0x80, 0x07, -0x20, 0x43, 0x00, 0x68, 0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, -0xc0, 0x46, 0xda, 0x80, 0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, -0xfe, 0xf7, 0x10, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, +0xfe, 0xf7, 0xae, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, +0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x7d, 0xff, 0x08, 0xbc, +0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x78, 0xff, 0x08, 0xbc, 0x18, 0x47, +0x00, 0xb5, 0xfe, 0xf7, 0x73, 0xff, 0x08, 0xbc, +0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x6e, 0xff, 0x08, 0xbc, 0x18, 0x47, +0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, +0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, +0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x5a, 0xff, +0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x55, 0xff, 0x08, 0xbc, +0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff, 0x08, 0xbc, 0x18, 0x47, +0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, +0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, +0x08, 0xa9, 0xfe, 0xf7, 0x27, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x04, 0xf0, +0x75, 0xfa, 0x02, 0x20, 0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, +0xfe, 0xf7, 0x5c, 0xfe, 0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, +0x00, 0xb5, 0xfe, 0xf7, 0x2d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, +0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x0c, 0xff, +0xfa, 0x88, 0x12, 0x49, 0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, +0x0f, 0xd0, 0x04, 0x70, 0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, +0xc8, 0x82, 0xb8, 0x68, 0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, +0x48, 0x83, 0xf8, 0x68, 0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21, +0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, +0x00, 0x21, 0xfe, 0xf7, 0x2b, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, +0x00, 0xb5, 0xfe, 0xf7, 0xf7, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, +0xfe, 0xf7, 0xf2, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, +0xed, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xe8, 0xfe, +0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, +0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, +0xfe, 0xf7, 0xc2, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43, +0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42, +0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, +0xfe, 0xf7, 0xf0, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68, +0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80, +0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xe0, 0xfd, +0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, +0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x8f, 0xfe, 0xf8, 0x88, +0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b, +0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, +0x00, 0x21, 0xfe, 0xf7, 0xbf, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68, +0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, -0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, -0xbf, 0xfe, 0xf8, 0x88, 0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, -0x02, 0xd3, 0x0a, 0x4b, 0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xef, 0xfd, 0x01, 0x20, -0x03, 0xe0, 0xb9, 0x68, 0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, -0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x86, 0xb0, 0x07, 0x1c, 0x03, 0xf0, -0x5b, 0xfd, 0x38, 0x1c, 0x02, 0xa9, 0xfe, 0xf7, 0x97, 0xfe, 0x01, 0x27, -0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x01, 0x68, -0xc0, 0x46, 0x04, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x05, 0x91, 0x81, 0x68, -0xc0, 0x46, 0x00, 0x91, 0x00, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46, -0x02, 0xa8, 0xfe, 0xf7, 0xc1, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x18, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68, -0x80, 0x68, 0xfe, 0xf7, 0x79, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, +0x80, 0xb5, 0x86, 0xb0, 0x07, 0x1c, 0x04, 0xf0, 0x33, 0xf9, 0x38, 0x1c, +0x02, 0xa9, 0xfe, 0xf7, 0x67, 0xfe, 0x01, 0x27, 0x02, 0xab, 0x5f, 0x70, +0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68, 0xc0, 0x46, 0x04, 0x91, +0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68, +0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46, +0x02, 0xa8, 0xfe, 0xf7, 0x91, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68, +0x80, 0x68, 0xfe, 0xf7, 0x49, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, -0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x76, 0xfe, 0x01, 0xab, 0x5c, 0x80, -0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xa1, 0xfd, 0x04, 0xb0, +0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x46, 0xfe, 0x01, 0xab, 0x5c, 0x80, +0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x71, 0xfd, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, -0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x64, 0xfe, 0x01, 0xab, 0x5f, 0x80, -0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x90, 0xfd, 0x04, 0xb0, 0x80, 0xbc, +0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x34, 0xfe, 0x01, 0xab, 0x5f, 0x80, +0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x60, 0xfd, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a, 0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0, 0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27, 0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27, -0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0x2c, 0xfe, 0x01, 0xab, 0x5f, 0x80, -0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x66, 0xfd, 0x20, 0x1c, 0x04, 0xb0, +0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xfc, 0xfd, 0x01, 0xab, 0x5f, 0x80, +0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x36, 0xfd, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, -0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0, -0x69, 0x46, 0xfe, 0xf7, 0x17, 0xfe, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab, -0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x4f, 0xfd, 0x01, 0x20, -0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, -0x00, 0xb5, 0xfe, 0xf7, 0x1d, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47, -0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, -0x80, 0xb5, 0x01, 0x20, 0x14, 0x4f, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, -0x48, 0x71, 0x13, 0x48, 0xfe, 0xf7, 0xd6, 0xfb, 0x01, 0x20, 0x40, 0x02, -0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0xf9, 0x1d, 0xb9, 0x31, -0x08, 0x70, 0x0e, 0x4a, 0x01, 0x23, 0x1b, 0x04, 0x11, 0x68, 0x0b, 0x40, -0x15, 0x21, 0x00, 0x2b, 0x05, 0xd1, 0x13, 0x68, 0x1b, 0x0c, 0x08, 0xd1, -0x12, 0x68, 0x92, 0x0a, 0x05, 0xd3, 0x08, 0x4a, 0xc0, 0x46, 0xd1, 0x60, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x06, 0x4a, 0xc0, 0x46, 0x11, 0x64, -0xf8, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xa9, 0x9d, 0x21, 0x40, -0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, +0xe7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, +0x00, 0x21, 0xfe, 0xf7, 0x1f, 0xfd, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, +0xed, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, -0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xbb, 0xfd, 0x00, 0x20, -0x01, 0xab, 0x58, 0x70, 0x10, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29, -0x0a, 0xd1, 0x03, 0xf0, 0xb9, 0xfc, 0x03, 0x90, 0x04, 0x97, 0x03, 0x98, -0x00, 0x28, 0x06, 0xd0, 0x68, 0x46, 0x02, 0xf0, 0x15, 0xf8, 0x04, 0xe0, -0x03, 0x97, 0x04, 0x90, 0xf8, 0xe7, 0x00, 0x20, 0x00, 0x90, 0x02, 0xab, -0x00, 0x98, 0xc0, 0x46, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, -0xdb, 0xfc, 0x38, 0x1c, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, -0x38, 0x1c, 0xfe, 0xf7, 0x8d, 0xfd, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, -0x01, 0x24, 0x20, 0x1c, 0x12, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, -0x00, 0x20, 0x00, 0x06, 0x00, 0x0e, 0x13, 0xd0, 0xf8, 0x88, 0x0f, 0x4a, -0x90, 0x42, 0x02, 0xd0, 0x0e, 0x4b, 0x98, 0x42, 0x08, 0xd1, 0xb9, 0x68, -0x27, 0x1c, 0x90, 0x42, 0x00, 0xd0, 0x00, 0x27, 0x38, 0x06, 0x00, 0x0e, -0x03, 0xf0, 0xa0, 0xfc, 0x03, 0xf0, 0x76, 0xfc, 0x02, 0x90, 0x00, 0xe0, -0x02, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xa7, 0xfc, 0x20, 0x1c, -0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0xed, 0xfe, 0x00, 0x00, 0xfe, 0xca, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, -0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0x04, 0xf0, 0x9b, 0xf8, 0x01, 0x34, -0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, -0x14, 0x1c, 0x0d, 0x1c, 0x06, 0x1c, 0x1f, 0x1c, 0x1b, 0x4b, 0x32, 0x04, -0x12, 0x0c, 0x3c, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x2a, 0xfb, 0x32, 0x0c, -0x17, 0x4b, 0x3e, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x24, 0xfb, 0x15, 0x4b, -0x2a, 0x04, 0x12, 0x0c, 0x40, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x1d, 0xfb, -0x2a, 0x0c, 0x11, 0x4b, 0x42, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x17, 0xfb, -0x0e, 0x4b, 0x22, 0x04, 0x12, 0x0c, 0x44, 0x21, 0x02, 0x20, 0xfe, 0xf7, -0x10, 0xfb, 0x22, 0x0c, 0x0a, 0x4b, 0x46, 0x21, 0x02, 0x20, 0xfe, 0xf7, -0x0a, 0xfb, 0x08, 0x4b, 0x3a, 0x04, 0x12, 0x0c, 0x48, 0x21, 0x02, 0x20, -0xfe, 0xf7, 0x03, 0xfb, 0x3a, 0x0c, 0x04, 0x4b, -0x4a, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0xfd, 0xfa, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x7b, 0xb7, 0x21, 0x40, 0x88, 0xb5, 0x11, 0x27, -0x3f, 0x04, 0x38, 0x62, 0x79, 0x62, 0xba, 0x62, 0xfb, 0x62, 0x04, 0x20, -0xff, 0xf7, 0xaa, 0xff, 0x07, 0x48, 0x40, 0x6b, 0xc0, 0x46, 0x00, 0x90, -0x00, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, 0x01, 0xd1, 0x01, 0x20, -0x00, 0xe0, 0x00, 0x20, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x00, 0x00, 0x11, 0x40, 0xf0, 0xb5, 0x8a, 0xb0, 0x00, 0x24, 0x05, 0x94, -0x69, 0x49, 0xc9, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x68, 0x4a, 0x11, 0x68, -0x01, 0x22, 0x12, 0x04, 0x0a, 0x40, 0x17, 0x21, 0x66, 0x4e, 0x00, 0x2a, -0x06, 0xd1, 0x64, 0x4a, 0x13, 0x68, 0x1b, 0x0c, 0x04, 0xd1, 0x12, 0x68, -0x92, 0x0a, 0x01, 0xd3, 0xf1, 0x60, 0x02, 0xe0, 0x61, 0x4a, 0xc0, 0x46, -0x11, 0x64, 0x61, 0x49, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x03, 0x29, -0x54, 0xd1, 0xe9, 0x21, 0x01, 0x91, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, -0x06, 0x94, 0x06, 0x99, 0x8a, 0x00, 0x5b, 0x49, 0x8a, 0x58, 0x00, 0x2a, -0x73, 0xd0, 0x80, 0x20, 0x02, 0x90, 0x06, 0x98, 0x81, 0x00, 0x57, 0x48, -0x41, 0x58, 0x02, 0x9a, 0x11, 0x43, 0x02, 0x91, 0x00, 0x24, 0x00, 0x27, -0x25, 0x02, 0x28, 0x1c, 0x38, 0x43, 0x09, 0x90, 0x09, 0x98, 0x00, 0x04, -0x51, 0x4b, 0x18, 0x43, 0x04, 0x90, 0x09, 0x98, 0xef, 0x23, 0xdb, 0x05, -0x18, 0x43, 0x03, 0x90, 0x06, 0x98, 0x80, 0x00, 0x4b, 0x49, 0x08, 0x58, -0x00, 0x04, 0x03, 0x99, 0x08, 0x43, 0x03, 0x90, 0x00, 0x2f, 0x02, 0xd1, -0x03, 0x98, 0xc0, 0x46, 0x70, 0x60, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, -0x04, 0x98, 0xff, 0xf7, 0x89, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x99, -0xc0, 0x46, 0xb1, 0x60, 0x03, 0x99, 0xc0, 0x46, 0x71, 0x60, 0x5c, 0xe0, -0x79, 0x1c, 0x0f, 0x04, 0x3f, 0x0c, 0x17, 0x2f, 0xd1, 0xdd, 0x61, 0x1c, -0x0c, 0x04, 0x24, 0x0c, 0x16, 0x2c, 0xca, 0xdd, 0x06, 0x99, 0x01, 0x31, -0x06, 0x91, 0x06, 0x99, 0x89, 0x00, 0x37, 0x4a, 0x51, 0x58, 0x00, 0x29, -0xb7, 0xd1, 0x48, 0xe0, 0xbf, 0x21, 0xc9, 0x43, 0x04, 0x91, 0xff, 0x21, -0x02, 0x91, 0x97, 0x21, 0x01, 0x91, 0x06, 0x94, 0x06, 0x99, 0x89, 0x00, -0x31, 0x4f, 0x79, 0x58, 0x00, 0x29, 0x1c, 0xd0, 0x09, 0x94, 0x08, 0x94, -0x06, 0x98, 0x80, 0x00, 0x38, 0x58, 0xc0, 0x46, 0x07, 0x90, 0x07, 0x98, -0x00, 0x04, 0x26, 0xe0, 0x05, 0x98, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, -0x03, 0x90, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, -0x49, 0xff, 0x00, 0x28, 0x23, 0xd1, 0x09, 0x99, 0x01, 0x31, 0x09, 0x91, -0x17, 0x29, 0x06, 0xd8, 0x00, 0xe0, 0x1c, 0xe0, 0x08, 0x98, 0x00, 0x02, -0x09, 0x99, 0x08, 0x43, 0x07, 0xe0, 0x08, 0x99, 0x01, 0x31, 0x08, 0x91, -0x17, 0x29, 0x0a, 0xd8, 0x09, 0x94, 0x08, 0x98, 0x00, 0x02, 0x07, 0x99, -0x09, 0x04, 0x08, 0x43, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x05, 0x90, -0xd6, 0xe7, 0x06, 0x99, 0x01, 0x31, 0x06, 0x91, 0x06, 0x99, 0x89, 0x00, -0x79, 0x58, 0x00, 0x29, 0xc4, 0xd1, 0x0c, 0x4a, 0x11, 0x68, 0x49, 0x0c, -0x05, 0xd2, 0x11, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x11, 0x68, 0x89, 0x0a, -0x03, 0xd3, 0x00, 0x99, 0xc0, 0x46, 0xf1, 0x60, 0x03, 0xe0, 0x00, 0x99, -0x06, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x40, 0x01, 0x18, 0x40, -0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, -0x00, 0x00, 0x18, 0x40, 0x30, 0x6e, 0x21, 0x40, 0x43, 0xff, 0x00, 0x00, -0x0c, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x82, 0xb0, 0x00, 0x20, 0x01, 0x90, -0x1e, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x1b, 0xd1, 0x40, 0x88, 0x00, 0x28, -0x18, 0xd1, 0x68, 0x46, 0x01, 0xf0, 0x6a, 0xfe, 0x00, 0x28, 0x13, 0xd1, -0xa8, 0x20, 0x01, 0xf0, 0xab, 0xfe, 0x18, 0x4f, 0x00, 0x28, 0x11, 0xd0, -0x04, 0x20, 0xff, 0xf7, 0x97, 0xfe, 0x78, 0x6b, 0xc0, 0x46, 0x01, 0x90, -0x01, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, 0x06, 0xd1, 0x00, 0x20, -0x01, 0xf0, 0x9a, 0xfe, 0x02, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfe, -0x00, 0x23, 0xdb, 0x43, 0x18, 0x1c, 0x19, 0x1c, 0x1a, 0x1c, 0xff, 0xf7, -0xc7, 0xfe, 0x00, 0x28, 0x03, 0xd1, 0xff, 0xf7, 0xdf, 0xfe, 0x00, 0x28, -0xe5, 0xd0, 0x38, 0x6a, 0x79, 0x6a, 0xba, 0x6a, 0xfb, 0x6a, 0xff, 0xf7, -0x7c, 0xfe, 0xde, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x11, 0x40, -0xff, 0xb5, 0x85, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, -0x01, 0x23, 0x5b, 0x04, 0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x82, 0xe0, -0x26, 0x1c, 0x43, 0x4d, 0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, -0x09, 0x05, 0x41, 0x48, 0x41, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, -0x06, 0x1c, 0x80, 0x2f, 0x00, 0xd8, 0x3d, 0x1c, 0x3e, 0x4a, 0x51, 0x69, -0xc0, 0x46, 0x03, 0x91, 0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0xff, 0x23, -0x01, 0x33, 0x19, 0x43, 0x39, 0x4b, 0xc0, 0x46, 0x59, 0x61, 0xff, 0x23, -0x01, 0x33, 0x9a, 0x43, 0x36, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, -0x12, 0x05, 0xd1, 0x60, 0x33, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, -0x11, 0x61, 0x31, 0x4a, 0xff, 0x23, 0x01, 0x33, 0x91, 0x69, 0x19, 0x43, -0x91, 0x61, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x85, 0x21, 0x89, 0x04, -0x04, 0x91, 0x00, 0x2f, 0x34, 0xd0, 0x28, 0x48, 0x86, 0x42, 0x04, 0xd1, -0x30, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0xd5, 0xfe, 0x2a, 0x1c, -0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x01, 0x20, 0x06, 0x99, 0x05, 0x9a, -0x33, 0x1c, 0xfe, 0xf7, 0x5d, 0xf9, 0x22, 0x48, 0x22, 0x49, 0x4a, 0x68, -0x52, 0x0a, 0x09, 0xd3, 0xff, 0x21, 0x01, 0x31, 0x20, 0x4a, 0xc0, 0x46, -0x11, 0x60, 0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x13, 0xe0, -0x01, 0x38, 0xf0, 0xd1, 0xf9, 0xe7, 0x7f, 0x1b, 0x0e, 0xd0, 0x15, 0x48, -0x86, 0x42, 0x01, 0xd1, 0x64, 0x19, 0x00, 0xe0, 0x76, 0x19, 0x06, 0x99, -0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, -0x05, 0x1c, 0xca, 0xe7, 0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, -0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, -0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, -0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, 0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, -0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, +0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0xb5, 0xfe, 0xf7, +0xdb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x85, 0xb0, +0x01, 0xa9, 0xfe, 0xf7, 0xbb, 0xfd, 0x00, 0x20, 0x01, 0xab, 0x58, 0x70, +0x10, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29, 0x0a, 0xd1, 0x04, 0xf0, +0xc7, 0xf8, 0x03, 0x90, 0x04, 0x97, 0x03, 0x98, 0x00, 0x28, 0x06, 0xd0, +0x68, 0x46, 0x02, 0xf0, 0xe5, 0xfb, 0x04, 0xe0, 0x03, 0x97, 0x04, 0x90, +0xf8, 0xe7, 0x00, 0x20, 0x00, 0x90, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46, +0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xdb, 0xfc, 0x38, 0x1c, +0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, +0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, +0x8d, 0xfd, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 0x01, 0x24, 0x20, 0x1c, +0x12, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, 0x00, 0x20, 0x00, 0x06, +0x00, 0x0e, 0x13, 0xd0, 0xf8, 0x88, 0x0f, 0x4a, 0x90, 0x42, 0x02, 0xd0, +0x0e, 0x4b, 0x98, 0x42, 0x08, 0xd1, 0xb9, 0x68, 0x27, 0x1c, 0x90, 0x42, +0x00, 0xd0, 0x00, 0x27, 0x38, 0x06, 0x00, 0x0e, 0x04, 0xf0, 0x88, 0xf8, +0x04, 0xf0, 0x84, 0xf8, 0x02, 0x90, 0x00, 0xe0, 0x02, 0x94, 0x68, 0x46, +0x00, 0x21, 0xfe, 0xf7, 0xa7, 0xfc, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xed, 0xfe, 0x00, 0x00, +0xfe, 0xca, 0x00, 0x00, 0xf1, 0xb5, 0xd6, 0xb0, +0x00, 0x20, 0x81, 0x00, 0x56, 0x9c, 0x0a, 0x19, 0x12, 0x6a, 0x6b, 0x46, +0x5a, 0x50, 0x01, 0x30, 0x10, 0x28, 0xf6, 0xdb, 0x10, 0x20, 0x82, 0x00, +0x11, 0x1c, 0x69, 0x44, 0x40, 0x39, 0x4b, 0x6b, 0x0f, 0x6a, 0x7b, 0x40, +0x8f, 0x68, 0x7b, 0x40, 0x09, 0x68, 0x59, 0x40, 0x4b, 0x00, 0xc9, 0x0f, +0x19, 0x43, 0x6b, 0x46, 0x99, 0x50, 0x01, 0x30, 0x50, 0x28, 0xec, 0xdb, +0x56, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x55, 0x91, 0x42, 0x68, 0xc0, 0x46, +0x54, 0x92, 0x86, 0x68, 0xc0, 0x46, 0x53, 0x96, 0xc5, 0x68, 0xc0, 0x46, +0x52, 0x95, 0x04, 0x69, 0xc0, 0x46, 0x51, 0x94, 0x48, 0x01, 0xcb, 0x0e, +0x18, 0x43, 0x13, 0x1c, 0x33, 0x40, 0x07, 0x1c, 0x28, 0x1c, 0x90, 0x43, +0x18, 0x43, 0x38, 0x18, 0x00, 0x19, 0x00, 0x9b, 0xc0, 0x18, 0xcf, 0x4b, +0xc0, 0x18, 0x93, 0x07, 0x92, 0x08, 0x13, 0x43, 0x42, 0x01, 0x1f, 0x1c, +0xc3, 0x0e, 0x1a, 0x43, 0x0b, 0x1c, 0x3b, 0x40, 0x14, 0x1c, 0x32, 0x1c, +0x8a, 0x43, 0x1a, 0x43, 0xa2, 0x18, 0x52, 0x19, 0x01, 0x9b, 0xd2, 0x18, +0xc5, 0x4b, 0xd4, 0x18, 0x8a, 0x07, 0x89, 0x08, 0x11, 0x43, 0x62, 0x01, +0xe3, 0x0e, 0x1a, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x15, 0x1c, 0x3a, 0x1c, +0x82, 0x43, 0x1a, 0x43, 0xaa, 0x18, 0x92, 0x19, 0x02, 0x9b, 0xd2, 0x18, +0xbc, 0x4b, 0xd2, 0x18, 0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, +0x57, 0x01, 0xd5, 0x0e, 0x3d, 0x43, 0x27, 0x1c, 0x07, 0x40, 0x0e, 0x1c, +0xa6, 0x43, 0x37, 0x43, 0xed, 0x19, 0xeb, 0x18, 0x03, 0x9f, 0xdf, 0x19, +0xb3, 0x4b, 0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, +0xfd, 0x0e, 0x2b, 0x43, 0x15, 0x1c, 0x25, 0x40, 0x1e, 0x1c, 0x03, 0x1c, +0x93, 0x43, 0x2b, 0x43, 0xf3, 0x18, 0x59, 0x18, 0x04, 0x9b, 0xc9, 0x18, +0xaa, 0x4b, 0xc9, 0x18, 0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, +0xcd, 0x0e, 0x1d, 0x43, 0x3e, 0x1c, 0x16, 0x40, 0x23, 0x1c, 0xbb, 0x43, +0x33, 0x43, 0xeb, 0x18, 0x18, 0x18, 0x05, 0x9b, 0xc0, 0x18, 0xa2, 0x4b, +0xc0, 0x18, 0xbb, 0x07, 0xbf, 0x08, 0x1f, 0x43, 0x43, 0x01, 0xc5, 0x0e, +0x2b, 0x43, 0x0d, 0x1c, 0x3d, 0x40, 0x1e, 0x1c, 0x13, 0x1c, 0x8b, 0x43, +0x2b, 0x43, 0xf3, 0x18, 0x1b, 0x19, 0x06, 0x9c, 0x1c, 0x19, 0x99, 0x4b, +0xe4, 0x18, 0x8b, 0x07, 0x89, 0x08, 0x19, 0x43, 0x63, 0x01, 0xe5, 0x0e, +0x1d, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x3e, 0x1c, 0x86, 0x43, 0x33, 0x43, +0xeb, 0x18, 0x9a, 0x18, 0x07, 0x9b, 0xd2, 0x18, 0x90, 0x4b, 0xd2, 0x18, +0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, 0x57, 0x01, 0xd5, 0x0e, +0x2f, 0x43, 0x25, 0x1c, 0x05, 0x40, 0x3e, 0x1c, 0x0f, 0x1c, 0xa7, 0x43, +0x2f, 0x43, 0xf5, 0x19, 0xeb, 0x18, 0x08, 0x9f, 0xdf, 0x19, 0x87, 0x4b, +0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, 0xfd, 0x0e, +0x1d, 0x43, 0x16, 0x1c, 0x26, 0x40, 0x03, 0x1c, 0x93, 0x43, 0x33, 0x43, +0xeb, 0x18, 0x59, 0x18, 0x09, 0x9b, 0xc9, 0x18, 0x7e, 0x4b, 0xc9, 0x18, +0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, 0xcd, 0x0e, 0x1d, 0x43, +0x3b, 0x1c, 0x13, 0x40, 0x26, 0x1c, 0xbe, 0x43, 0x33, 0x43, 0xeb, 0x18, +0x18, 0x18, 0x0a, 0x9b, 0xc0, 0x18, 0x76, 0x4b, 0xc0, 0x18, 0x23, 0x1c, +0xbc, 0x07, 0xbf, 0x08, 0x27, 0x43, 0x44, 0x01, 0xc5, 0x0e, 0x2c, 0x43, +0x0d, 0x1c, 0x3d, 0x40, 0x26, 0x1c, 0x14, 0x1c, 0x8c, 0x43, 0x2c, 0x43, +0x35, 0x19, 0xeb, 0x18, 0x0b, 0x9c, 0x1c, 0x19, +0x6c, 0x4b, 0xe4, 0x18, 0x8b, 0x07, 0x89, 0x08, 0x19, 0x43, 0x63, 0x01, +0xe5, 0x0e, 0x1d, 0x43, 0x03, 0x1c, 0x0b, 0x40, 0x3e, 0x1c, 0x86, 0x43, +0x33, 0x43, 0xeb, 0x18, 0x9a, 0x18, 0x0c, 0x9b, 0xd2, 0x18, 0x64, 0x4b, +0xd2, 0x18, 0x3b, 0x1c, 0x87, 0x07, 0x80, 0x08, 0x38, 0x43, 0x57, 0x01, +0xd5, 0x0e, 0x3d, 0x43, 0x27, 0x1c, 0x07, 0x40, 0x0e, 0x1c, 0xa6, 0x43, +0x37, 0x43, 0xed, 0x19, 0xeb, 0x18, 0x0d, 0x9f, 0xdf, 0x19, 0x5b, 0x4b, +0xff, 0x18, 0xa3, 0x07, 0xa4, 0x08, 0x1c, 0x43, 0x7b, 0x01, 0xfd, 0x0e, +0x1d, 0x43, 0x13, 0x1c, 0x23, 0x40, 0x06, 0x1c, 0x96, 0x43, 0x33, 0x43, +0xeb, 0x18, 0x59, 0x18, 0x0e, 0x9b, 0xc9, 0x18, 0x52, 0x4b, 0xc9, 0x18, +0x93, 0x07, 0x92, 0x08, 0x1a, 0x43, 0x4b, 0x01, 0xcd, 0x0e, 0x2b, 0x43, +0x3d, 0x1c, 0x15, 0x40, 0x1e, 0x1c, 0x23, 0x1c, 0xbb, 0x43, 0x2b, 0x43, +0xf3, 0x18, 0x18, 0x18, 0x0f, 0x9b, 0xc0, 0x18, 0x49, 0x4b, 0xc0, 0x18, +0x23, 0x1c, 0xbc, 0x07, 0xbf, 0x08, 0x27, 0x43, 0x10, 0x24, 0x50, 0x94, +0x44, 0x01, 0xc5, 0x0e, 0x25, 0x43, 0x0e, 0x1c, 0x3e, 0x40, 0x14, 0x1c, +0x8c, 0x43, 0x34, 0x43, 0x2c, 0x19, 0xe3, 0x18, 0x50, 0x9c, 0xa5, 0x00, +0x6c, 0x46, 0x64, 0x59, 0x1c, 0x19, 0x3e, 0x4b, 0xe4, 0x18, 0x13, 0x1c, +0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 0x0f, 0x43, 0x01, 0x1c, 0x20, 0x1c, +0x50, 0x9c, 0x01, 0x34, 0x50, 0x94, 0x14, 0x2c, 0xe2, 0xdb, 0x14, 0x24, +0x45, 0x01, 0xc6, 0x0e, 0x2e, 0x43, 0x0d, 0x1c, 0x7d, 0x40, 0x55, 0x40, +0x75, 0x19, 0xeb, 0x18, 0xa5, 0x00, 0x6e, 0x46, 0x75, 0x59, 0x5d, 0x19, +0x31, 0x4b, 0xed, 0x18, 0x13, 0x1c, 0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, +0x0f, 0x43, 0x01, 0x1c, 0x28, 0x1c, 0x01, 0x34, 0x28, 0x2c, 0xe7, 0xdb, +0x28, 0x24, 0x50, 0x94, 0x44, 0x01, 0xc5, 0x0e, 0x25, 0x43, 0x3c, 0x1c, +0x14, 0x43, 0x0c, 0x40, 0x3e, 0x1c, 0x16, 0x40, 0x34, 0x43, 0x2c, 0x19, +0xe3, 0x18, 0x50, 0x9c, 0xa5, 0x00, 0x6c, 0x46, 0x64, 0x59, 0x1c, 0x19, +0x23, 0x4b, 0xe4, 0x18, 0x13, 0x1c, 0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, +0x0f, 0x43, 0x01, 0x1c, 0x20, 0x1c, 0x50, 0x9c, 0x01, 0x34, 0x50, 0x94, +0x3c, 0x2c, 0xe1, 0xdb, 0x3c, 0x24, 0x45, 0x01, 0xc6, 0x0e, 0x2e, 0x43, +0x0d, 0x1c, 0x7d, 0x40, 0x55, 0x40, 0x75, 0x19, 0xeb, 0x18, 0xa6, 0x00, +0x6d, 0x46, 0xad, 0x59, 0x5d, 0x19, 0x17, 0x4b, 0xed, 0x18, 0x13, 0x1c, +0x3a, 0x1c, 0x8f, 0x07, 0x89, 0x08, 0x0f, 0x43, 0x01, 0x1c, 0x28, 0x1c, +0x01, 0x34, 0x50, 0x2c, 0xe7, 0xdb, 0x55, 0x9c, 0x20, 0x18, 0x56, 0x9c, +0xc0, 0x46, 0x20, 0x60, 0x54, 0x98, 0x40, 0x18, 0x56, 0x9c, 0xc0, 0x46, +0x60, 0x60, 0x53, 0x9e, 0xf0, 0x19, 0x56, 0x9c, 0xc0, 0x46, 0xa0, 0x60, +0x52, 0x9d, 0xa8, 0x18, 0x56, 0x9c, 0xc0, 0x46, 0xe0, 0x60, 0x51, 0x9c, +0xe0, 0x18, 0x56, 0x9c, 0xc0, 0x46, 0x20, 0x61, 0x57, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x99, 0x79, 0x82, 0x5a, 0xa1, 0xeb, 0xd9, 0x6e, +0xdc, 0xbc, 0x1b, 0x8f, 0xd6, 0xc1, 0x62, 0xca, 0x88, 0xb4, 0x8a, 0x08, +0x89, 0x07, 0x00, 0xd0, 0x01, 0x32, 0x00, 0x21, 0x00, 0x2a, 0x1e, 0xdd, +0x07, 0x78, 0x00, 0xab, 0x1f, 0x70, 0x47, 0x78, 0xc0, 0x46, 0x5f, 0x70, +0x87, 0x78, 0xc0, 0x46, 0x9f, 0x70, 0xc7, 0x78, 0xc0, 0x46, 0xdf, 0x70, +0xdb, 0x78, 0xc0, 0x46, 0x03, 0x70, 0x00, 0xab, 0x9b, 0x78, 0xc0, 0x46, +0x43, 0x70, 0x00, 0xab, 0x5b, 0x78, 0xc0, 0x46, +0x83, 0x70, 0x00, 0xab, 0x1b, 0x78, 0xc0, 0x46, 0xc3, 0x70, 0x04, 0x30, +0x01, 0x31, 0x91, 0x42, 0xe0, 0xdb, 0x88, 0xbc, 0x70, 0x47, 0x00, 0x21, +0xc1, 0x61, 0x09, 0x4a, 0xc0, 0x46, 0x02, 0x60, 0x08, 0x4a, 0xc0, 0x46, +0x42, 0x60, 0x08, 0x4a, 0xc0, 0x46, 0x82, 0x60, 0x07, 0x4a, 0xc0, 0x46, +0xc2, 0x60, 0x07, 0x4a, 0xc0, 0x46, 0x02, 0x61, 0x41, 0x61, 0x81, 0x61, +0x70, 0x47, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, +0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xf0, 0xe1, 0xd2, 0xc3, +0xf0, 0xb5, 0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0xe1, 0x00, 0x78, 0x69, +0x41, 0x18, 0x81, 0x42, 0x02, 0xd2, 0xb8, 0x69, 0x01, 0x30, 0xb8, 0x61, +0x79, 0x61, 0x61, 0x0f, 0xb8, 0x69, 0x40, 0x18, 0xb8, 0x61, 0x40, 0x2c, +0x14, 0xdb, 0xfe, 0x1d, 0x19, 0x36, 0x00, 0x20, 0x29, 0x78, 0x3a, 0x18, +0x20, 0x32, 0x11, 0x70, 0x01, 0x35, 0x01, 0x30, 0x40, 0x28, 0xf7, 0xd3, +0x40, 0x21, 0x30, 0x1c, 0xff, 0xf7, 0x96, 0xff, 0x38, 0x1c, 0xff, 0xf7, +0xaf, 0xfd, 0x40, 0x3c, 0x40, 0x2c, 0xec, 0xda, 0x00, 0x20, 0x00, 0x2c, +0x07, 0xd9, 0x29, 0x78, 0x3a, 0x18, 0x20, 0x32, 0x11, 0x70, 0x01, 0x35, +0x01, 0x30, 0xa0, 0x42, 0xf7, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0xf8, 0xb5, 0x07, 0x1c, 0xd3, 0x00, 0x78, 0x69, 0xc6, 0x18, 0x86, 0x42, +0x02, 0xd2, 0xb8, 0x69, 0x01, 0x30, 0xb8, 0x61, 0x7e, 0x61, 0x53, 0x0f, +0xb8, 0x69, 0xc0, 0x18, 0xb8, 0x61, 0x00, 0x90, 0x00, 0x20, 0x00, 0x2a, +0x07, 0xdd, 0x0b, 0x78, 0x3c, 0x18, 0x20, 0x34, 0x23, 0x70, 0x01, 0x31, +0x01, 0x30, 0x90, 0x42, 0xf7, 0xdb, 0x80, 0x20, 0xd1, 0x19, 0x20, 0x31, +0x08, 0x70, 0x54, 0x1c, 0xfd, 0x1d, 0x19, 0x35, 0x38, 0x2c, 0x1c, 0xdd, +0x38, 0x19, 0x20, 0x30, 0x00, 0x21, 0x40, 0x22, 0x12, 0x1b, 0x00, 0x2a, +0x05, 0xdd, 0x00, 0x23, 0x03, 0x70, 0x01, 0x30, 0x01, 0x31, 0x8a, 0x42, +0xfa, 0xdc, 0x28, 0x1c, 0x21, 0x1c, 0xff, 0xf7, 0x4d, 0xff, 0x38, 0x1c, +0xff, 0xf7, 0x66, 0xfd, 0x28, 0x1c, 0x00, 0x21, 0x00, 0x23, 0x03, 0x70, +0x01, 0x30, 0x01, 0x31, 0x38, 0x29, 0xfa, 0xdb, 0x0c, 0xe0, 0x38, 0x19, +0x20, 0x30, 0x00, 0x21, 0x38, 0x22, 0x12, 0x1b, 0x00, 0x2a, 0x05, 0xdd, +0x00, 0x23, 0x03, 0x70, 0x01, 0x30, 0x01, 0x31, 0x8a, 0x42, 0xfa, 0xdc, +0x28, 0x1c, 0x21, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x00, 0x98, 0xc0, 0x46, +0xb8, 0x65, 0xfe, 0x65, 0x38, 0x1c, 0xff, 0xf7, 0x45, 0xfd, 0x01, 0x20, +0xf8, 0x61, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x0c, 0x1c, +0x05, 0x1c, 0x17, 0x1c, 0x38, 0x1c, 0x00, 0x2f, 0x04, 0xda, 0x40, 0x42, +0x80, 0x06, 0x80, 0x0e, 0x40, 0x42, 0x01, 0xe0, 0x80, 0x06, 0x80, 0x0e, +0x00, 0x28, 0x07, 0xd1, 0x28, 0x1c, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, +0x57, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0x00, 0x2f, +0x00, 0xda, 0x3f, 0x30, 0x80, 0x11, 0x00, 0x28, 0x07, 0xdd, 0x86, 0x01, +0x28, 0x1c, 0x21, 0x1c, 0x32, 0x1c, 0xff, 0xf7, 0x47, 0xff, 0xa4, 0x19, +0xbf, 0x1b, 0x00, 0x2f, 0xeb, 0xd0, 0x28, 0x1c, 0x21, 0x1c, 0x3a, 0x1c, +0xff, 0xf7, 0x74, 0xff, 0xe5, 0xe7, 0x98, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, +0x30, 0x20, 0x00, 0xab, 0x18, 0x70, 0xf8, 0x69, 0x00, 0x28, 0x04, 0xd1, +0x69, 0x46, 0x00, 0x22, 0x38, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0x14, 0x21, +0x38, 0x1c, 0xff, 0xf7, 0xe3, 0xfe, 0x00, 0x20, +0x81, 0x00, 0x79, 0x58, 0x02, 0xc4, 0x01, 0x30, 0x05, 0x28, 0xf9, 0xdb, +0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0x98, 0xb0, 0x07, 0x1c, +0x78, 0x68, 0x40, 0x28, 0x10, 0xd9, 0x68, 0x46, 0xff, 0xf7, 0xf9, 0xfe, +0x68, 0x46, 0x06, 0xcf, 0x08, 0x3f, 0xff, 0xf7, 0xa7, 0xff, 0xf8, 0x1d, +0xc5, 0x30, 0x69, 0x46, 0x04, 0x1c, 0xff, 0xf7, 0xd0, 0xff, 0x14, 0x20, +0x78, 0x60, 0x3c, 0x60, 0x00, 0x20, 0x00, 0x24, 0x39, 0x18, 0xca, 0x1d, +0x39, 0x32, 0x14, 0x72, 0x80, 0x31, 0x4c, 0x72, 0x7b, 0x68, 0x83, 0x42, +0x06, 0xd9, 0x3b, 0x68, 0x5d, 0x1c, 0x3d, 0x60, 0x1b, 0x78, 0xc0, 0x46, +0x13, 0x72, 0x4b, 0x72, 0x15, 0x7a, 0x36, 0x23, 0x6b, 0x40, 0x13, 0x72, +0x4a, 0x7a, 0x5c, 0x23, 0x5a, 0x40, 0x4a, 0x72, 0x01, 0x30, 0x40, 0x28, +0xe4, 0xd3, 0x18, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, +0xe0, 0xb0, 0x14, 0x1c, 0x0f, 0x1c, 0x00, 0x25, 0xae, 0x00, 0x01, 0x20, +0xf1, 0x1d, 0x1d, 0x31, 0x02, 0xf0, 0x10, 0xfe, 0x01, 0x04, 0x00, 0x91, +0x01, 0x20, 0xf1, 0x1d, 0x1b, 0x31, 0x02, 0xf0, 0x09, 0xfe, 0x00, 0x99, +0x08, 0x43, 0x19, 0xa9, 0x71, 0x18, 0x88, 0x60, 0x01, 0x35, 0x10, 0x2d, +0xea, 0xd3, 0x1b, 0xa8, 0x19, 0x90, 0x40, 0x20, 0x1a, 0x90, 0x19, 0xa8, +0xff, 0xf7, 0xa7, 0xff, 0x01, 0xa8, 0xff, 0xf7, 0xa6, 0xfe, 0x40, 0x22, +0x01, 0xa8, 0x2b, 0xa9, 0xff, 0xf7, 0x54, 0xff, 0x00, 0x2f, 0x0b, 0xd0, +0x40, 0x2f, 0x01, 0xd9, 0x40, 0x25, 0x00, 0xe0, 0x3d, 0x1c, 0x60, 0x99, +0x01, 0xa8, 0x2a, 0x1c, 0xff, 0xf7, 0x48, 0xff, 0x7f, 0x1b, 0xf3, 0xd1, +0x51, 0xa8, 0x01, 0xa9, 0x07, 0x1c, 0xff, 0xf7, 0x70, 0xff, 0x01, 0xa8, +0xff, 0xf7, 0x8b, 0xfe, 0x40, 0x22, 0x01, 0xa8, 0x3b, 0xa9, 0x01, 0x31, +0xff, 0xf7, 0x38, 0xff, 0x14, 0x22, 0x01, 0xa8, 0x39, 0x1c, 0xff, 0xf7, +0x33, 0xff, 0x56, 0xa8, 0x01, 0xa9, 0xff, 0xf7, 0x5e, 0xff, 0x00, 0x20, +0x82, 0x00, 0x19, 0xa9, 0x51, 0x18, 0xc0, 0x31, 0x49, 0x6b, 0x02, 0xc4, +0x01, 0x30, 0x05, 0x28, 0xf6, 0xd3, 0x63, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 0x00, 0x24, 0x00, 0x2f, +0x04, 0xd3, 0x04, 0xf0, 0x15, 0xf9, 0x01, 0x34, 0xbc, 0x42, 0xfa, 0xd9, +0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x14, 0x1c, 0x0d, 0x1c, +0x06, 0x1c, 0x1f, 0x1c, 0x1b, 0x4b, 0x32, 0x04, 0x12, 0x0c, 0x3c, 0x21, +0x02, 0x20, 0xfd, 0xf7, 0x8a, 0xff, 0x32, 0x0c, 0x17, 0x4b, 0x3e, 0x21, +0x02, 0x20, 0xfd, 0xf7, 0x84, 0xff, 0x15, 0x4b, 0x2a, 0x04, 0x12, 0x0c, +0x40, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x7d, 0xff, 0x2a, 0x0c, 0x11, 0x4b, +0x42, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x77, 0xff, 0x0e, 0x4b, 0x22, 0x04, +0x12, 0x0c, 0x44, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x70, 0xff, 0x22, 0x0c, +0x0a, 0x4b, 0x46, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x6a, 0xff, 0x08, 0x4b, +0x3a, 0x04, 0x12, 0x0c, 0x48, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x63, 0xff, +0x3a, 0x0c, 0x04, 0x4b, 0x4a, 0x21, 0x02, 0x20, 0xfd, 0xf7, 0x5d, 0xff, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xd9, 0xbf, 0x21, 0x40, +0x88, 0xb5, 0x11, 0x27, 0x3f, 0x04, 0x38, 0x62, 0x79, 0x62, 0xba, 0x62, +0xfb, 0x62, 0x04, 0x20, 0xff, 0xf7, 0xaa, 0xff, 0x07, 0x48, 0x40, 0x6b, +0xc0, 0x46, 0x00, 0x90, 0x00, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, +0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, +0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, +0xf0, 0xb5, 0x8a, 0xb0, 0x00, 0x24, 0x05, 0x94, 0x69, 0x49, 0xc9, 0x68, +0xc0, 0x46, 0x00, 0x91, 0x68, 0x4a, 0x11, 0x68, 0x01, 0x22, 0x12, 0x04, +0x0a, 0x40, 0x17, 0x21, 0x66, 0x4e, 0x00, 0x2a, 0x06, 0xd1, 0x64, 0x4a, +0x13, 0x68, 0x1b, 0x0c, 0x04, 0xd1, 0x12, 0x68, 0x92, 0x0a, 0x01, 0xd3, +0xf1, 0x60, 0x02, 0xe0, 0x61, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0x61, 0x49, +0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x03, 0x29, 0x54, 0xd1, 0xe9, 0x21, +0x01, 0x91, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, 0x06, 0x94, 0x06, 0x99, +0x8a, 0x00, 0x5b, 0x49, 0x8a, 0x58, 0x00, 0x2a, 0x73, 0xd0, 0x80, 0x20, +0x02, 0x90, 0x06, 0x98, 0x81, 0x00, 0x57, 0x48, 0x41, 0x58, 0x02, 0x9a, +0x11, 0x43, 0x02, 0x91, 0x00, 0x24, 0x00, 0x27, 0x25, 0x02, 0x28, 0x1c, +0x38, 0x43, 0x09, 0x90, 0x09, 0x98, 0x00, 0x04, 0x51, 0x4b, 0x18, 0x43, +0x04, 0x90, 0x09, 0x98, 0xef, 0x23, 0xdb, 0x05, 0x18, 0x43, 0x03, 0x90, +0x06, 0x98, 0x80, 0x00, 0x4b, 0x49, 0x08, 0x58, 0x00, 0x04, 0x03, 0x99, +0x08, 0x43, 0x03, 0x90, 0x00, 0x2f, 0x02, 0xd1, 0x03, 0x98, 0xc0, 0x46, +0x70, 0x60, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, +0x89, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, +0x03, 0x99, 0xc0, 0x46, 0x71, 0x60, 0x5c, 0xe0, 0x79, 0x1c, 0x0f, 0x04, +0x3f, 0x0c, 0x17, 0x2f, 0xd1, 0xdd, 0x61, 0x1c, 0x0c, 0x04, 0x24, 0x0c, +0x16, 0x2c, 0xca, 0xdd, 0x06, 0x99, 0x01, 0x31, 0x06, 0x91, 0x06, 0x99, +0x89, 0x00, 0x37, 0x4a, 0x51, 0x58, 0x00, 0x29, 0xb7, 0xd1, 0x48, 0xe0, +0xbf, 0x21, 0xc9, 0x43, 0x04, 0x91, 0xff, 0x21, 0x02, 0x91, 0x97, 0x21, +0x01, 0x91, 0x06, 0x94, 0x06, 0x99, 0x89, 0x00, 0x31, 0x4f, 0x79, 0x58, +0x00, 0x29, 0x1c, 0xd0, 0x09, 0x94, 0x08, 0x94, 0x06, 0x98, 0x80, 0x00, +0x38, 0x58, 0xc0, 0x46, 0x07, 0x90, 0x07, 0x98, 0x00, 0x04, 0x26, 0xe0, +0x05, 0x98, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x03, 0x90, 0x01, 0x9b, +0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, 0x49, 0xff, 0x00, 0x28, +0x23, 0xd1, 0x09, 0x99, 0x01, 0x31, 0x09, 0x91, 0x17, 0x29, 0x06, 0xd8, +0x00, 0xe0, 0x1c, 0xe0, 0x08, 0x98, 0x00, 0x02, 0x09, 0x99, 0x08, 0x43, +0x07, 0xe0, 0x08, 0x99, 0x01, 0x31, 0x08, 0x91, 0x17, 0x29, 0x0a, 0xd8, +0x09, 0x94, 0x08, 0x98, 0x00, 0x02, 0x07, 0x99, 0x09, 0x04, 0x08, 0x43, +0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x05, 0x90, 0xd6, 0xe7, 0x06, 0x99, +0x01, 0x31, 0x06, 0x91, 0x06, 0x99, 0x89, 0x00, 0x79, 0x58, 0x00, 0x29, +0xc4, 0xd1, 0x0c, 0x4a, 0x11, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x11, 0x68, +0x09, 0x0c, 0x06, 0xd1, 0x11, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x00, 0x99, +0xc0, 0x46, 0xf1, 0x60, 0x03, 0xe0, 0x00, 0x99, 0x06, 0x4a, 0xc0, 0x46, +0x11, 0x64, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x40, 0x01, 0x18, 0x40, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, +0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x18, 0x40, 0x30, 0x6e, 0x21, 0x40, +0x43, 0xff, 0x00, 0x00, 0x0c, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x82, 0xb0, +0x00, 0x20, 0x01, 0x90, 0x1e, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x1b, 0xd1, +0x40, 0x88, 0x00, 0x28, 0x18, 0xd1, 0x68, 0x46, 0x01, 0xf0, 0x9a, 0xfe, +0x00, 0x28, 0x13, 0xd1, 0xa8, 0x20, 0x01, 0xf0, +0xdb, 0xfe, 0x18, 0x4f, 0x00, 0x28, 0x11, 0xd0, 0x04, 0x20, 0xff, 0xf7, +0x97, 0xfe, 0x78, 0x6b, 0xc0, 0x46, 0x01, 0x90, 0x01, 0x98, 0x80, 0x07, +0x80, 0x0f, 0x03, 0x28, 0x06, 0xd1, 0x00, 0x20, 0x01, 0xf0, 0xca, 0xfe, +0x02, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23, 0x00, 0x22, +0x00, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfe, 0x00, 0x23, 0xdb, 0x43, +0x18, 0x1c, 0x19, 0x1c, 0x1a, 0x1c, 0xff, 0xf7, 0xc7, 0xfe, 0x00, 0x28, +0x03, 0xd1, 0xff, 0xf7, 0xdf, 0xfe, 0x00, 0x28, 0xe5, 0xd0, 0x38, 0x6a, +0x79, 0x6a, 0xba, 0x6a, 0xfb, 0x6a, 0xff, 0xf7, 0x7c, 0xfe, 0xde, 0xe7, +0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x11, 0x40, 0xff, 0xb5, 0x85, 0xb0, +0x14, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x01, 0x23, 0x5b, 0x04, +0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x82, 0xe0, 0x26, 0x1c, 0x43, 0x4d, +0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x41, 0x48, +0x41, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, +0x00, 0xd8, 0x3d, 0x1c, 0x3e, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, +0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0xff, 0x23, 0x01, 0x33, 0x19, 0x43, +0x39, 0x4b, 0xc0, 0x46, 0x59, 0x61, 0xff, 0x23, 0x01, 0x33, 0x9a, 0x43, +0x36, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, +0x33, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x31, 0x4a, +0xff, 0x23, 0x01, 0x33, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, 0x01, 0x22, +0x12, 0x05, 0x11, 0x61, 0x85, 0x21, 0x89, 0x04, 0x04, 0x91, 0x00, 0x2f, +0x34, 0xd0, 0x28, 0x48, 0x86, 0x42, 0x04, 0xd1, 0x30, 0x1c, 0x21, 0x1c, +0x2a, 0x1c, 0x03, 0xf0, 0x4f, 0xff, 0x2a, 0x1c, 0x04, 0x98, 0x02, 0x43, +0x00, 0x92, 0x01, 0x20, 0x06, 0x99, 0x05, 0x9a, 0x33, 0x1c, 0xfd, 0xf7, +0xbd, 0xfd, 0x22, 0x48, 0x22, 0x49, 0x4a, 0x68, 0x52, 0x0a, 0x09, 0xd3, +0xff, 0x21, 0x01, 0x31, 0x20, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x00, 0x28, +0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x13, 0xe0, 0x01, 0x38, 0xf0, 0xd1, +0xf9, 0xe7, 0x7f, 0x1b, 0x0e, 0xd0, 0x15, 0x48, 0x86, 0x42, 0x01, 0xd1, +0x64, 0x19, 0x00, 0xe0, 0x76, 0x19, 0x06, 0x99, 0x49, 0x19, 0x06, 0x91, +0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, 0x05, 0x1c, 0xca, 0xe7, +0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, +0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, +0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, +0x81, 0x61, 0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x50, 0xab, 0x20, 0x40, +0x00, 0x00, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, +0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0xb0, 0xff, 0xb5, 0x85, 0xb0, +0x04, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x01, 0x23, 0x5b, 0x04, +0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x7d, 0xe0, 0x26, 0x1c, 0x40, 0x4d, +0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x3e, 0x48, +0x3e, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, +0x00, 0xd8, 0x3d, 0x1c, 0x3b, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, +0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0x10, 0x23, 0x19, 0x43, 0x37, 0x4b, +0xc0, 0x46, 0x59, 0x61, 0x10, 0x23, 0x9a, 0x43, +0x34, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, +0x31, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x2f, 0x4a, +0x10, 0x23, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, 0x1a, 0x04, 0x11, 0x61, +0x21, 0x21, 0x09, 0x05, 0x04, 0x91, 0x00, 0x2f, 0x33, 0xd0, 0x2a, 0x1c, +0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x00, 0x20, 0x06, 0x99, 0x07, 0x9a, +0x33, 0x1c, 0xfd, 0xf7, 0x27, 0xfd, 0x25, 0x48, 0x25, 0x49, 0x4a, 0x68, +0x52, 0x09, 0x08, 0xd3, 0x10, 0x21, 0x24, 0x4a, 0xc0, 0x46, 0x11, 0x60, +0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x1b, 0xe0, 0x01, 0x38, +0xf1, 0xd1, 0xf9, 0xe7, 0x19, 0x48, 0x86, 0x42, 0x04, 0xd1, 0x20, 0x1c, +0x31, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0x96, 0xfe, 0x7f, 0x1b, 0x0e, 0xd0, +0x14, 0x48, 0x86, 0x42, 0x01, 0xd0, 0x76, 0x19, 0x00, 0xe0, 0x64, 0x19, +0x06, 0x99, 0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, +0x28, 0x1c, 0x05, 0x1c, 0xcb, 0xe7, 0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, +0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, +0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, +0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, 0x11, 0x61, 0x01, 0x98, +0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xff, 0x00, 0x00, +0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0xb0, -0xff, 0xb5, 0x85, 0xb0, 0x04, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, -0x01, 0x23, 0x5b, 0x04, 0x9f, 0x42, 0x01, 0xd9, -0x0f, 0x20, 0x7d, 0xe0, 0x26, 0x1c, 0x40, 0x4d, 0xaf, 0x42, 0x00, 0xd2, -0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x3e, 0x48, 0x3e, 0x4b, 0x99, 0x42, -0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, 0x00, 0xd8, 0x3d, 0x1c, -0x3b, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, 0x92, 0x69, 0xc0, 0x46, -0x02, 0x92, 0x10, 0x23, 0x19, 0x43, 0x37, 0x4b, 0xc0, 0x46, 0x59, 0x61, -0x10, 0x23, 0x9a, 0x43, 0x34, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, -0x12, 0x05, 0xd1, 0x60, 0x31, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, -0x11, 0x61, 0x2f, 0x4a, 0x10, 0x23, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, -0x1a, 0x04, 0x11, 0x61, 0x21, 0x21, 0x09, 0x05, 0x04, 0x91, 0x00, 0x2f, -0x33, 0xd0, 0x2a, 0x1c, 0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x00, 0x20, -0x06, 0x99, 0x07, 0x9a, 0x33, 0x1c, 0xfe, 0xf7, 0xc7, 0xf8, 0x25, 0x48, -0x25, 0x49, 0x4a, 0x68, 0x52, 0x09, 0x08, 0xd3, 0x10, 0x21, 0x24, 0x4a, -0xc0, 0x46, 0x11, 0x60, 0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, -0x1b, 0xe0, 0x01, 0x38, 0xf1, 0xd1, 0xf9, 0xe7, 0x19, 0x48, 0x86, 0x42, -0x04, 0xd1, 0x20, 0x1c, 0x31, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0x1c, 0xfe, -0x7f, 0x1b, 0x0e, 0xd0, 0x14, 0x48, 0x86, 0x42, 0x01, 0xd0, 0x76, 0x19, -0x00, 0xe0, 0x64, 0x19, 0x06, 0x99, 0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, -0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, 0x05, 0x1c, 0xcb, 0xe7, 0x0f, 0x48, -0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, -0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, -0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, -0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xf0, 0xff, 0x00, 0x00, 0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, -0x00, 0x00, 0x00, 0xb0, 0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, -0x0a, 0x70, 0x01, 0x30, 0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, -0xa0, 0x82, 0x20, 0x40, 0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, -0x01, 0x32, 0x88, 0x42, 0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, -0x02, 0xd3, 0x40, 0x1a, 0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, -0x01, 0x1c, 0xff, 0x27, 0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, -0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, -0x4b, 0x00, 0x59, 0x18, 0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, -0xdb, 0x00, 0xd7, 0x50, 0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, -0x57, 0x60, 0x8b, 0x68, 0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, -0x13, 0x61, 0x4b, 0x69, 0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, -0xd1, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, -0x04, 0x28, 0xd9, 0xdb, 0x38, 0x1c, 0xf6, 0xe7, 0xd0, 0xab, 0x20, 0x40, -0xf7, 0xb5, 0xc5, 0xb0, 0x14, 0x1c, 0x00, 0x20, 0x11, 0x21, 0x21, 0x40, -0x5f, 0xd0, 0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x5b, 0x4a, -0x51, 0x58, 0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, -0x04, 0xe0, 0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, -0x00, 0x28, 0x4c, 0xd0, 0x00, 0x22, 0x01, 0x92, 0x00, 0x92, 0x40, 0x23, -0x00, 0x21, 0x00, 0x20, 0x03, 0xaa, 0x00, 0xf0, -0x8f, 0xfa, 0x05, 0xa9, 0x00, 0x20, 0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, -0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42, 0x05, 0xd1, 0x01, 0x9a, 0x01, 0x32, -0x12, 0x06, 0x12, 0x0e, 0x01, 0x92, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06, -0x00, 0x0e, 0x10, 0x28, 0xed, 0xdb, 0x01, 0x9a, 0x00, 0x2a, 0x4f, 0xd0, -0x45, 0x9b, 0x04, 0x2b, 0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, -0x80, 0x0d, 0x00, 0x22, 0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x03, 0xaa, -0x00, 0xf0, 0x6a, 0xfa, 0x00, 0x21, 0x01, 0x91, 0x03, 0xa8, 0x06, 0x99, -0x49, 0x0c, 0x89, 0x05, 0x2a, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, -0x46, 0x9b, 0x9a, 0x42, 0x12, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, -0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, -0x00, 0xf0, 0x52, 0xfa, 0x01, 0x99, 0x03, 0x9d, 0x48, 0x1c, 0x01, 0x06, -0x09, 0x0e, 0x01, 0x91, 0x0f, 0xe0, 0x57, 0xe0, 0x48, 0x01, 0x86, 0x0d, -0x00, 0x22, 0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, -0x00, 0xf0, 0x40, 0xfa, 0x03, 0xa8, 0x06, 0x99, 0x49, 0x0c, 0x89, 0x05, -0xd7, 0xd1, 0x01, 0x99, 0x00, 0x29, 0x11, 0xd1, 0xff, 0x20, 0x3f, 0xe0, +0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30, +0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40, +0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42, +0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a, +0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27, +0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18, +0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18, +0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50, +0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68, +0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69, +0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc, +0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb, +0x38, 0x1c, 0xf6, 0xe7, 0xd0, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0, +0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0, +0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58, +0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0, +0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28, +0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21, +0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20, +0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1, +0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06, +0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c, +0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22, +0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, +0x00, 0xf0, 0x68, 0xfa, 0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, +0x49, 0x0c, 0x89, 0x05, 0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, +0x45, 0x9b, 0x9a, 0x42, 0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, +0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, +0x00, 0xf0, 0x50, 0xfa, 0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06, +0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22, +0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, +0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1, +0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92, -0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, 0x00, 0xf0, 0x2a, 0xfa, -0x03, 0x9d, 0x01, 0xe0, 0x20, 0x0a, 0xed, 0xd2, 0x01, 0x20, 0x00, 0x04, -0x20, 0x43, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, -0x50, 0x50, 0x30, 0x1c, 0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x45, 0x9b, -0x04, 0x2b, 0x00, 0xd0, 0x0c, 0x20, 0x02, 0x90, 0xb0, 0x60, 0x00, 0x20, -0x20, 0x21, 0x21, 0x40, 0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, -0x02, 0x98, 0x28, 0x18, 0xff, 0x21, 0xff, 0x30, 0x08, 0x30, 0x09, 0x31, -0xff, 0xf7, 0x12, 0xff, 0x43, 0x01, 0x18, 0x18, 0xc0, 0x00, 0x02, 0x99, -0x40, 0x1a, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21, 0x21, 0x40, 0x50, 0x29, -0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60, 0x38, 0x1c, 0x48, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xff, 0x20, 0xf9, 0xe7, 0xd0, 0xab, 0x20, 0x40, -0x80, 0xb4, 0x00, 0x23, 0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, -0x7b, 0x40, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, -0xd8, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, -0xc6, 0xb0, 0x04, 0x28, 0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, -0x45, 0x91, 0x41, 0x4a, 0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, -0xc0, 0x43, 0x76, 0xe0, 0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, -0x18, 0x18, 0xc0, 0x00, 0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, -0x00, 0x21, 0x02, 0x91, 0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, -0xff, 0x21, 0x68, 0x1e, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe, 0x61, 0x68, -0x40, 0x18, 0x01, 0x90, 0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, -0xaf, 0x1b, 0x09, 0xe0, 0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, -0xff, 0xf7, 0xc1, 0xfe, 0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, -0x00, 0x22, 0x00, 0x92, 0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, -0x00, 0xf0, 0x9e, 0xf9, 0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, -0xc0, 0x43, 0x02, 0x99, 0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, -0xed, 0x1b, 0xa0, 0x68, 0xa8, 0x42, 0x00, 0xd1, -0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99, 0xcf, 0x43, 0x00, 0x22, -0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, -0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90, 0x05, 0x98, 0x00, 0x0a, -0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x05, 0x90, 0xff, 0x23, -0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21, 0x03, 0xa8, 0xff, 0xf7, -0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99, 0x99, 0x43, 0x00, 0x06, -0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90, 0x0c, 0x23, 0x00, 0x21, -0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xbb, 0xf9, 0x00, 0x20, 0x45, 0x99, -0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43, 0x61, 0x60, 0xa1, 0x60, -0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb4, 0x4c, 0x42, -0x00, 0x29, 0x00, 0xdb, 0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, -0x21, 0xda, 0x12, 0x4d, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, -0x01, 0x2a, 0x05, 0xd0, 0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, -0x01, 0x69, 0x0b, 0xe0, 0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, -0x0f, 0xd3, 0x05, 0xe0, 0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, -0x09, 0xd3, 0x09, 0x1b, 0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, -0xc1, 0x68, 0x09, 0x19, 0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, -0xf6, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, -0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, -0xd2, 0x00, 0x2c, 0x49, 0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, -0x00, 0x23, 0xdb, 0x43, 0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, -0x01, 0xd2, 0x18, 0x1c, 0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, -0x21, 0x69, 0x8a, 0x42, 0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, -0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, -0x07, 0xfe, 0x61, 0x68, 0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, -0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x07, 0xfe, 0xc2, 0x19, 0xff, 0x21, -0x09, 0x31, 0x8a, 0x42, 0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, -0x0b, 0x1a, 0x03, 0x93, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, -0xe1, 0xf8, 0xe0, 0x68, 0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, -0x5d, 0x19, 0xff, 0x1a, 0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, -0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, -0x3b, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, -0xe0, 0x60, 0x02, 0x98, 0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, -0xc2, 0xd8, 0x02, 0x98, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, -0x00, 0x21, 0x01, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, -0x30, 0x49, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, -0x04, 0x28, 0x01, 0xda, 0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, -0x02, 0x9a, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, -0x01, 0xd9, 0x22, 0x69, 0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, -0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, -0xa1, 0xfd, 0x61, 0x68, 0x40, 0x18, 0x00, 0x90, -0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, -0xa0, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23, 0x5b, 0x04, 0x19, 0x43, -0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32, 0x91, 0x42, 0x13, 0xd9, -0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c, 0x1e, 0x1c, 0x00, 0xf0, -0xd0, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19, 0xe0, 0x60, 0x21, 0x69, -0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b, 0x01, 0x98, 0x30, 0x18, -0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e, 0x30, 0x1c, 0x2a, 0x1c, -0x3b, 0x1c, 0x00, 0xf0, 0xbc, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, -0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0x01, 0x98, -0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xb9, 0xd8, 0x01, 0x98, -0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, -0xb0, 0xb5, 0xc3, 0xb0, 0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, -0x06, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, -0x6b, 0x0c, 0x04, 0xd2, 0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x62, 0x09, 0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, -0x40, 0x68, 0x0c, 0x23, 0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, -0x11, 0x2c, 0x0d, 0xd0, 0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, -0x14, 0x2c, 0x0a, 0xd1, 0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, -0x03, 0x98, 0x07, 0x06, 0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, -0x02, 0x9f, 0x38, 0x1c, 0xdb, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, -0x03, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, -0xfb, 0xd3, 0x70, 0x47, 0xd0, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, -0x9f, 0xf9, 0x57, 0x20, 0x02, 0xf0, 0xfc, 0xf8, 0x02, 0xf0, 0x70, 0xf8, -0x00, 0x0a, 0xfb, 0xd3, 0x02, 0xf0, 0x7e, 0xf9, 0x08, 0xbc, 0x18, 0x47, -0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x07, 0x9a, 0x1f, 0x1c, 0xff, 0x23, -0x01, 0x33, 0x1a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, -0x00, 0x0c, 0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x82, 0xf9, -0x53, 0x20, 0x02, 0xf0, 0xdf, 0xf8, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, -0x02, 0xf0, 0xda, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xd7, 0xf8, 0x30, 0x1c, -0x02, 0xf0, 0xd4, 0xf8, 0x02, 0xf0, 0x5a, 0xf9, 0xff, 0xf7, 0xce, 0xff, -0x02, 0xf0, 0x6e, 0xf9, 0x54, 0x20, 0x02, 0xf0, 0xcb, 0xf8, 0x00, 0x98, -0x02, 0xf0, 0xc8, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xc5, 0xf8, 0x30, 0x1c, -0x14, 0xe0, 0x02, 0xf0, 0x61, 0xf9, 0x52, 0x20, 0x02, 0xf0, 0xbe, 0xf8, -0x01, 0x98, 0x02, 0xf0, 0xbb, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xb8, 0xf8, -0x30, 0x1c, 0x02, 0xf0, 0xb5, 0xf8, 0x00, 0x20, 0x02, 0xf0, 0xb2, 0xf8, -0x00, 0x20, 0x02, 0xf0, 0xaf, 0xf8, 0x00, 0x20, 0x02, 0xf0, 0xac, 0xf8, -0x00, 0x20, 0x02, 0xf0, 0xa9, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, -0x1b, 0xf8, 0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, -0x27, 0xf9, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, -0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x40, 0x02, 0x08, 0x43, 0x05, 0x1c, -0x02, 0xf0, 0x32, 0xf9, 0x53, 0x20, 0x02, 0xf0, 0x8f, 0xf8, 0x28, 0x0c, -0x06, 0x1c, 0x02, 0xf0, 0x8b, 0xf8, 0x28, 0x0a, 0x01, 0x90, 0x00, 0x90, -0x02, 0xf0, 0x86, 0xf8, 0x28, 0x1c, 0x02, 0xf0, -0x83, 0xf8, 0x02, 0xf0, 0x09, 0xf9, 0xff, 0xf7, 0x7d, 0xff, 0x02, 0xf0, -0x1d, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x7a, 0xf8, 0x30, 0x1c, 0x02, 0xf0, -0x77, 0xf8, 0x00, 0x98, 0x02, 0xf0, 0x74, 0xf8, 0x28, 0x1c, 0x02, 0xf0, -0x71, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0, -0x6b, 0xf8, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xef, 0xf8, 0x02, 0xf0, -0x05, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x62, 0xf8, 0x30, 0x1c, 0x02, 0xf0, -0x5f, 0xf8, 0x01, 0x98, 0x02, 0xf0, 0x5c, 0xf8, 0x28, 0x1c, 0x02, 0xf0, -0x59, 0xf8, 0x02, 0xf0, 0xdf, 0xf8, 0xff, 0xf7, 0x53, 0xff, 0x02, 0xb0, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, -0x80, 0xb5, 0x01, 0xf0, 0x89, 0xf8, 0x06, 0x4f, 0xc0, 0x46, 0xf8, 0x60, -0x01, 0xf0, 0xe4, 0xf8, 0x78, 0x80, 0x01, 0xf0, 0xa5, 0xf8, 0x38, 0x71, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0xb5, 0x01, 0xf0, 0xf7, 0xf8, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x80, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x0b, 0x48, 0xc1, 0x68, -0x01, 0x29, 0x11, 0xd1, 0x02, 0x22, 0xc1, 0x6f, 0x0a, 0x43, 0xc2, 0x67, -0x08, 0x49, 0xc0, 0x46, 0x0a, 0x60, 0x80, 0x23, 0xc2, 0x6f, 0x1a, 0x43, -0xc2, 0x67, 0x0a, 0x60, 0x82, 0x22, 0x80, 0x30, 0x02, 0x60, 0x4a, 0x60, -0x00, 0x21, 0x81, 0x80, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x01, 0x11, 0x00, 0xf0, 0xb4, 0x49, 0x49, 0xca, 0x1d, 0x99, 0x32, -0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28, -0xfa, 0xd3, 0x45, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30, -0x20, 0x28, 0xfa, 0xd3, 0x42, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50, -0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65, -0x8f, 0x65, 0x3e, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60, -0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00, -0x09, 0x18, 0x49, 0x01, 0x34, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d, -0xf5, 0x33, 0x33, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x87, 0x23, 0x9b, 0x00, -0xcb, 0x18, 0x63, 0x63, 0xcf, 0x23, 0x9b, 0x00, 0xcb, 0x18, 0xb4, 0x18, -0xe3, 0x63, 0x30, 0x4b, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30, 0x02, 0x28, -0xe5, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf5, 0x31, 0x28, 0x4c, 0xc0, 0x46, -0xa1, 0x62, 0x61, 0x6b, 0xcf, 0x23, 0x9b, 0x00, 0xe1, 0x62, 0xc1, 0x18, -0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21, 0xe1, 0x64, -0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x25, 0x49, 0x0b, 0x69, 0xc0, 0x46, -0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66, 0x8b, 0x68, -0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66, 0x1f, 0x4b, -0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x67, 0x67, 0x1d, 0x4b, 0xc3, 0x18, -0x01, 0x26, 0xa3, 0x67, 0x66, 0x61, 0xe7, 0x61, 0xe3, 0x1d, 0x69, 0x33, -0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x19, 0x4b, 0xc0, 0x46, 0x13, 0x65, +0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa, +0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00, +0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c, +0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20, +0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40, +0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21, +0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01, +0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21, +0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60, +0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20, +0xf9, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23, +0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06, +0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06, +0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28, +0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a, +0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0, +0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, +0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91, +0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e, +0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90, +0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0, +0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe, +0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92, +0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9, +0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99, +0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68, +0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99, +0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, +0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90, +0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43, +0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21, +0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99, +0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, +0x08, 0x43, 0x05, 0x90, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, +0x00, 0xf0, 0xca, 0xf9, 0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, +0x50, 0x50, 0xc1, 0x43, 0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, +0x61, 0x61, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb, +0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d, +0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0, +0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0, +0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0, +0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b, +0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19, +0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00, +0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, +0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49, +0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43, +0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c, +0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42, +0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68, +0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68, +0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, +0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42, +0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93, +0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68, +0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a, +0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46, +0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, +0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98, +0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98, +0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, +0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91, +0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58, +0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda, +0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18, +0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69, +0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68, +0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68, +0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, +0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23, +0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32, +0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c, +0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19, +0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b, +0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, +0x01, 0x1c, 0x00, 0x9e, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, +0xcb, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, +0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, +0x00, 0x27, 0x00, 0x2f, 0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0, +0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00, +0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2, +0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09, +0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23, +0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0, +0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1, +0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06, +0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c, +0xdb, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20, +0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47, +0xd0, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x01, 0xfa, 0x57, 0x20, +0x02, 0xf0, 0x5e, 0xf9, 0x02, 0xf0, 0xd2, 0xf8, 0x00, 0x0a, 0xfb, 0xd3, +0x02, 0xf0, 0xe0, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0, +0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23, +0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32, +0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c, +0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0xdd, 0xf9, 0x53, 0x20, +0x02, 0xf0, 0x3a, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0, +0x35, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x32, 0xf9, 0x30, 0x1c, 0x02, 0xf0, +0x2f, 0xf9, 0x02, 0xf0, 0xb5, 0xf9, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0, +0xc9, 0xf9, 0x54, 0x20, 0x02, 0xf0, 0x26, 0xf9, 0x00, 0x98, 0x02, 0xf0, +0x23, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x20, 0xf9, 0x30, 0x1c, 0x14, 0xe0, +0x02, 0xf0, 0xbc, 0xf9, 0x52, 0x20, 0x02, 0xf0, 0x19, 0xf9, 0x01, 0x98, +0x02, 0xf0, 0x16, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x13, 0xf9, 0x30, 0x1c, +0x02, 0xf0, 0x10, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x0d, 0xf9, 0x00, 0x20, +0x02, 0xf0, 0x0a, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x07, 0xf9, 0x00, 0x20, +0x02, 0xf0, 0x04, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0x76, 0xf8, +0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0x82, 0xf9, +0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, +0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, +0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x40, 0x02, 0x08, 0x43, +0x05, 0x1c, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, +0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, +0x02, 0xf0, 0x7a, 0xf9, 0x53, 0x20, 0x02, 0xf0, 0xd7, 0xf8, 0x28, 0x0c, +0x06, 0x1c, 0x02, 0xf0, 0xd3, 0xf8, 0x28, 0x0a, 0x01, 0x90, 0x00, 0x90, +0x02, 0xf0, 0xce, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xcb, 0xf8, 0x02, 0xf0, +0x51, 0xf9, 0xff, 0xf7, 0x63, 0xff, 0x02, 0xf0, 0x65, 0xf9, 0x84, 0x20, +0x02, 0xf0, 0xc2, 0xf8, 0x30, 0x1c, 0x02, 0xf0, +0xbf, 0xf8, 0x00, 0x98, 0x02, 0xf0, 0xbc, 0xf8, 0x28, 0x1c, 0x02, 0xf0, +0xb9, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0, +0xb3, 0xf8, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0x37, 0xf9, 0x02, 0xf0, +0x4d, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0xaa, 0xf8, 0x30, 0x1c, 0x02, 0xf0, +0xa7, 0xf8, 0x01, 0x98, 0x02, 0xf0, 0xa4, 0xf8, 0x28, 0x1c, 0x02, 0xf0, +0xa1, 0xf8, 0x02, 0xf0, 0x27, 0xf9, 0xff, 0xf7, 0x39, 0xff, 0x07, 0x49, +0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, +0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x02, 0xb0, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, +0x80, 0xb5, 0x01, 0xf0, 0x91, 0xf8, 0x06, 0x4f, 0xc0, 0x46, 0xf8, 0x60, +0x01, 0xf0, 0xf4, 0xf8, 0x78, 0x80, 0x01, 0xf0, 0xb3, 0xf8, 0x38, 0x71, +0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, +0x00, 0xb5, 0x01, 0xf0, 0x07, 0xf9, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x80, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0xc1, 0x68, +0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23, 0x0a, 0x68, 0x1a, 0x43, +0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, +0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, +0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, +0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32, 0x00, 0x20, 0x00, 0x27, +0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28, 0xfa, 0xd3, 0x46, 0x4c, +0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, +0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x20, 0x28, +0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65, 0x8f, 0x65, 0x3f, 0x4d, +0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60, 0xaf, 0x61, 0xef, 0x60, +0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00, 0x09, 0x18, 0x49, 0x01, +0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d, 0xf9, 0x33, 0x34, 0x4c, +0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01, 0xcb, 0x18, 0x63, 0x63, +0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18, 0xe3, 0x63, 0x23, 0x23, +0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30, 0x02, 0x28, 0xe4, 0xdb, +0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c, 0xc0, 0x46, 0xa1, 0x62, +0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62, 0xc1, 0x18, 0x91, 0x62, +0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21, 0xe1, 0x64, 0x25, 0x49, +0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69, 0xc0, 0x46, 0x63, 0x65, +0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66, 0x8b, 0x68, 0xc0, 0x46, +0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66, 0x1e, 0x4b, 0xc0, 0x46, +0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01, 0xc3, 0x18, 0xa3, 0x67, +0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33, 0x66, 0x61, 0xe7, 0x61, +0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b, 0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d, 0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46, 0x53, 0x66, 0x89, 0x69, -0xc0, 0x46, 0x91, 0x66, 0x11, 0x49, 0xc0, 0x46, 0xd1, 0x66, 0x16, 0x67, -0x56, 0x67, 0x10, 0x4b, 0xc0, 0x18, 0x90, 0x67, 0x56, 0x61, 0xd7, 0x61, -0xd0, 0x1d, 0x69, 0x30, 0x07, 0x73, 0xf0, 0xbc, -0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, -0xd0, 0x2c, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x5c, 0x04, 0x00, 0x00, -0x30, 0x01, 0x18, 0x00, 0xf8, 0x28, 0x00, 0x80, 0x80, 0x54, 0xff, 0xff, -0x7c, 0x05, 0x00, 0x00, 0x38, 0x01, 0x18, 0x00, 0x90, 0x54, 0xff, 0xff, -0x7c, 0x07, 0x00, 0x00, 0x90, 0xb4, 0x00, 0x21, 0x1c, 0x4a, 0xbb, 0x23, -0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x72, 0x19, 0x23, 0xdb, 0x01, 0xd0, 0x18, -0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x81, 0x61, 0x59, 0x60, 0xb9, 0x72, -0x01, 0x27, 0x1f, 0x73, 0x19, 0x61, 0x17, 0x23, 0xdb, 0x01, 0xd3, 0x18, -0xd9, 0x63, 0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0xc3, 0x62, 0x3b, 0x60, -0x44, 0x69, 0xe4, 0x18, 0x04, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, -0xe4, 0x02, 0x44, 0x63, 0x0d, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0xc4, 0x6a, -0xc0, 0x46, 0x04, 0x62, 0x44, 0x69, 0xe4, 0x18, 0x0a, 0x4b, 0xe3, 0x18, -0xfb, 0x60, 0xc3, 0x6a, 0xc0, 0x46, 0x43, 0x62, 0x03, 0x6a, 0xc0, 0x46, -0xc3, 0x61, 0x81, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, -0x90, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, -0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22, -0x1c, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x70, 0x01, 0x20, -0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x72, 0x18, 0x48, 0x03, 0x1c, -0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37, -0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18, -0x33, 0x23, 0x9b, 0x01, 0xcc, 0x18, 0xfa, 0x60, 0x60, 0x61, 0x40, 0x20, -0xb8, 0x60, 0xa2, 0x61, 0xe2, 0x61, 0xca, 0x64, 0x0a, 0x66, 0x0d, 0x48, -0xc0, 0x46, 0xc2, 0x60, 0x0c, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e, -0xb8, 0x63, 0x0b, 0x48, 0x65, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x02, 0x68, -0xc0, 0x46, 0x8a, 0x83, 0x42, 0x68, 0xc0, 0x46, 0xca, 0x83, 0x80, 0x68, -0xc0, 0x46, 0x20, 0x80, 0x90, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x3c, 0xbd, 0x20, 0x40, 0x3c, 0xef, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, -0x40, 0x00, 0x14, 0x40, 0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, -0xcb, 0x1d, 0xff, 0x33, 0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, -0x06, 0x4a, 0xc0, 0x46, 0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, -0x58, 0x70, 0xbb, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x08, 0x72, 0x70, 0x47, -0xa8, 0x04, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, -0x2f, 0x4a, 0xc0, 0x46, 0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, -0x50, 0x61, 0x2d, 0x48, 0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, -0x53, 0x62, 0x00, 0x23, 0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, -0xd4, 0x1d, 0xff, 0x34, 0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, -0x1c, 0x1f, 0x7c, 0x61, 0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, -0x79, 0x61, 0xf8, 0x62, 0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, -0x22, 0x4f, 0xfe, 0x1d, 0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, -0xe6, 0x61, 0x51, 0x26, 0xb6, 0x03, 0x37, 0x61, 0xe4, 0x69, 0xc0, 0x46, -0x74, 0x61, 0x2f, 0x67, 0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, -0x75, 0x34, 0x7c, 0x60, 0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, -0xe6, 0x1d, 0x75, 0x36, 0x7e, 0x61, 0x19, 0x4f, -0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c, 0x00, 0x21, 0xff, 0x24, -0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50, 0x01, 0x31, 0xa1, 0x42, -0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27, 0xff, 0x02, 0x83, 0x00, -0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3, 0x00, 0x20, 0x81, 0x00, -0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3, 0xf0, 0xbc, 0x70, 0x47, -0x24, 0xa3, 0x20, 0x40, 0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, -0x24, 0xa9, 0x20, 0x40, 0x80, 0x01, 0x18, 0x00, 0x28, 0x03, 0x00, 0x80, -0x24, 0xa7, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, -0xa4, 0xa8, 0x20, 0x40, 0x88, 0x03, 0x00, 0x80, 0xb8, 0xb5, 0x2d, 0x48, -0xfd, 0xf7, 0xc6, 0xfa, 0x01, 0x20, 0x2c, 0x49, 0x0a, 0x68, 0x52, 0x0c, -0x06, 0xd2, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, -0x00, 0xd2, 0x00, 0x20, 0x04, 0x06, 0x24, 0x0e, 0x26, 0x4a, 0xd7, 0x1d, -0x0d, 0x37, 0x00, 0x23, 0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, -0x04, 0x2b, 0xfa, 0xd3, 0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, -0xd0, 0x61, 0xf8, 0x61, 0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, -0x13, 0x62, 0x3b, 0x62, 0x00, 0x27, 0x1c, 0x4b, 0x8d, 0x68, 0xc0, 0x46, -0x00, 0x95, 0x8d, 0x69, 0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, -0xdd, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, -0x5d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, -0x01, 0x37, 0x40, 0x2f, 0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, -0x5b, 0x07, 0x1c, 0x43, 0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, -0x2b, 0x09, 0x02, 0xd2, 0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, -0x03, 0xd3, 0x09, 0x49, 0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, -0x07, 0x48, 0xfd, 0xf7, 0x71, 0xfa, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x04, 0x02, 0xff, 0xff, -0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01, -0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64, -0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67, -0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46, -0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc, -0x70, 0x47, 0x00, 0x00, 0x58, 0x67, 0x21, 0x40, 0xc8, 0x2a, 0x00, 0x80, -0x3c, 0x2c, 0x00, 0x80, 0x00, 0xb5, 0x64, 0x21, 0x07, 0x48, 0xc0, 0x46, -0x01, 0x63, 0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, -0xc1, 0x63, 0x01, 0x64, 0x03, 0x48, 0x28, 0x22, 0x02, 0xf0, 0x06, 0xff, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x59, 0x03, 0xff, 0xff, -0x80, 0xb4, 0x01, 0x20, 0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, -0x3c, 0x20, 0x48, 0x60, 0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, -0x00, 0x20, 0x07, 0x4a, 0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, -0x01, 0x30, 0x10, 0x28, 0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, -0x50, 0x2d, 0x00, 0x80, 0x60, 0x2d, 0x00, 0x80, 0xd5, 0x4b, 0xff, 0xff, -0x12, 0x49, 0x13, 0x48, 0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, -0x08, 0x38, 0x11, 0x4b, 0xca, 0x18, 0xc1, 0x60, +0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46, 0xd1, 0x66, 0x16, 0x67, +0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67, 0x56, 0x67, 0xd7, 0x61, +0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73, +0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80, +0x64, 0x2d, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00, +0x7c, 0x29, 0x00, 0x80, 0xec, 0x54, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00, +0xfc, 0x54, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23, +0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23, 0xdb, 0x01, 0xd0, 0x18, +0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18, 0xc1, 0x61, 0x1c, 0x70, +0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60, 0xb9, 0x73, 0x59, 0x61, +0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60, 0x13, 0x4b, 0x51, 0x27, +0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69, 0xe4, 0x18, 0x44, 0x63, +0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02, 0x84, 0x63, 0x0e, 0x4c, +0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46, 0x44, 0x62, 0x84, 0x69, +0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60, 0x03, 0x6b, 0xc0, 0x46, +0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62, 0xc1, 0x63, 0x51, 0x64, +0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0xfc, 0x07, 0x00, 0x00, +0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22, 0x1b, 0x49, 0xc9, 0x23, +0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, +0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c, 0x00, 0x27, 0xdc, 0x1d, +0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37, 0x3f, 0x2f, 0xf8, 0xd3, +0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18, 0x33, 0x23, 0x9b, 0x01, +0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20, 0xf8, 0x60, 0xda, 0x61, +0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48, 0xc0, 0x46, 0xc2, 0x60, +0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e, 0xf8, 0x63, 0x0a, 0x48, +0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68, 0xc0, 0x46, 0x59, 0x80, +0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x3c, 0xbd, 0x20, 0x40, 0x3c, 0xef, 0x20, 0x40, +0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40, 0x00, 0x20, 0x0a, 0x49, +0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33, 0x3a, 0x33, 0x88, 0x61, +0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46, 0x10, 0x65, 0x50, 0x66, +0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23, 0x1b, 0x01, 0xd1, 0x18, +0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, +0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46, 0x11, 0x61, 0x01, 0x23, +0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48, 0xc0, 0x46, 0x10, 0x62, +0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23, 0x13, 0x63, 0x53, 0x63, +0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34, 0xfa, 0x34, 0x14, 0xc7, +0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61, 0x26, 0x4f, 0xc0, 0x46, +0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62, 0x3b, 0x63, 0x7b, 0x64, +0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d, 0xf9, 0x36, 0x22, 0x4d, +0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26, 0xb6, 0x03, 0x37, 0x61, +0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67, 0x1d, 0x4d, 0x09, 0x27, +0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60, 0x3d, 0x60, 0x1b, 0x4c, +0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36, 0x7e, 0x61, 0x19, 0x4f, +0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c, +0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50, +0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27, +0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3, +0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3, +0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40, 0x40, 0x01, 0x18, 0x00, +0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x80, 0x01, 0x18, 0x00, +0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, +0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0x08, 0x04, 0x00, 0x80, +0xb8, 0xb5, 0x2c, 0x48, 0xfc, 0xf7, 0x0a, 0xff, 0x01, 0x20, 0x2b, 0x49, +0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, +0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x04, 0x06, 0x24, 0x0e, +0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23, 0x00, 0x20, 0x9d, 0x00, +0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3, 0x01, 0x27, 0x3f, 0x05, +0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61, 0x00, 0x23, 0xdb, 0x43, +0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62, 0x00, 0x27, 0x1b, 0x4b, +0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69, 0xc0, 0x46, 0x00, 0x95, +0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x9d, 0x6b, +0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x1d, 0x6b, +0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f, 0xe8, 0xd3, 0x00, 0x27, +0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43, 0x01, 0xe0, 0x20, 0x60, +0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2, 0x80, 0x2f, 0xf8, 0xd3, +0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49, 0x4b, 0x6e, 0x01, 0x33, +0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, +0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x00, 0x21, +0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01, 0x64, 0x1a, 0xa4, 0x00, +0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64, 0x58, 0x64, 0x10, 0x53, +0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67, 0xdc, 0x62, 0x01, 0x31, +0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x48, 0x60, +0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, +0x58, 0x67, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, +0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63, 0x00, 0x21, 0xc9, 0x43, +0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63, 0x01, 0x64, 0x70, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20, 0x40, 0x02, 0x0a, 0x49, +0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60, 0x88, 0x60, 0x08, 0x48, +0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a, 0x87, 0x00, 0xcb, 0x68, +0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28, 0xf8, 0xd3, 0x80, 0xbc, +0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xf4, 0x2d, 0x00, 0x80, +0x49, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48, 0x67, 0x23, 0x9b, 0x01, +0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b, 0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48, 0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b, 0xca, 0x18, 0xc1, 0x60, -0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49, 0x67, 0x23, 0x9b, 0x01, -0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b, 0xc2, 0x18, 0xc8, 0x60, -0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00, 0x58, 0x1f, 0x21, 0x40, -0xb4, 0x2d, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00, 0x58, 0xef, 0x20, 0x40, -0xa0, 0x2d, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00, 0x58, 0x3f, 0x21, 0x40, -0xc8, 0x2d, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, -0x0a, 0x01, 0x12, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, -0x10, 0x63, 0x50, 0x63, 0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, -0x3a, 0x49, 0xc0, 0x46, 0xc8, 0x62, 0x08, 0x63, 0x48, 0x63, 0x20, 0x60, -0x01, 0x21, 0xe3, 0x1d, 0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, -0x98, 0x71, 0x98, 0x72, 0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, -0xe2, 0x1d, 0x49, 0x32, 0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, -0x51, 0x73, 0x59, 0x70, 0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, -0x90, 0x71, 0x90, 0x72, 0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, -0x18, 0x73, 0x02, 0x22, 0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, -0xba, 0x70, 0x58, 0x73, 0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, -0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, -0xf9, 0x72, 0x39, 0x73, 0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, -0x99, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, -0x1a, 0x72, 0x99, 0x71, 0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, -0xda, 0x72, 0x19, 0x73, 0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, -0xb9, 0x70, 0x58, 0x73, 0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, -0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, -0xf9, 0x72, 0x3a, 0x73, 0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, -0x9a, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, -0x1a, 0x72, 0x99, 0x71, 0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, -0xd9, 0x72, 0x20, 0x61, 0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, -0x70, 0x47, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, 0x68, 0x19, 0x00, 0x80, -0x81, 0x20, 0x00, 0x02, 0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, -0xc0, 0x00, 0x14, 0x00, 0x0a, 0x49, 0x13, 0x23, 0xdb, 0x01, 0xc8, 0x18, -0x25, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x63, 0x00, 0x21, 0xc2, 0x1d, +0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49, +0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b, +0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00, +0x58, 0x1f, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00, +0x58, 0xef, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00, +0x58, 0x3f, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, +0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19, 0x19, 0x23, 0xdb, 0x01, +0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63, 0x90, 0x63, 0x01, 0x31, +0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46, 0x08, 0x63, 0x48, 0x63, +0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d, 0x59, 0x33, 0x60, 0x60, +0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72, 0x59, 0x71, 0x58, 0x72, +0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32, 0x11, 0x73, 0x19, 0x70, +0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70, 0xd0, 0x73, 0xd8, 0x70, +0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72, 0x50, 0x71, 0x50, 0x72, +0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22, 0xe7, 0x1d, 0x69, 0x37, +0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73, 0x78, 0x70, 0xd8, 0x73, +0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, +0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73, 0xe3, 0x1d, 0x79, 0x33, +0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, +0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71, 0x9a, 0x72, 0x58, 0x71, +0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73, 0xe7, 0x1d, 0x89, 0x37, +0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73, 0x7a, 0x70, 0xd9, 0x73, +0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, +0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73, 0xe3, 0x1d, 0x99, 0x33, +0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, +0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71, 0x99, 0x72, 0x58, 0x71, +0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61, 0xe0, 0x60, 0x60, 0x61, +0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, +0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02, 0x01, 0x49, 0xc0, 0x46, +0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 0x09, 0x49, 0x0a, 0x4b, +0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60, 0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31, 0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61, 0x70, 0x47, 0x00, 0x00, -0xe8, 0x0d, 0x00, 0x80, 0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, -0x48, 0x80, 0x00, 0x20, 0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, -0xc0, 0x46, 0x48, 0x61, 0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, -0xc8, 0x29, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, -0xc2, 0x1d, 0x19, 0x32, 0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, -0x11, 0x71, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, -0xec, 0x05, 0x00, 0x80, 0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, -0x00, 0x21, 0xc2, 0x1d, 0x4d, 0x32, 0xc2, 0x60, +0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00, 0x06, 0x48, 0x07, 0x49, +0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20, 0x88, 0x80, 0xc8, 0x80, +0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x88, 0x61, 0x70, 0x47, +0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, +0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32, 0xc1, 0x60, 0x01, 0x61, +0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, +0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x09, 0x48, 0x0a, 0x4b, +0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d, 0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60, 0x70, 0x47, 0x00, 0x00, -0x58, 0x07, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0xb5, 0x0c, 0x49, -0x0c, 0x48, 0xfd, 0xf7, 0xea, 0xf8, 0x0c, 0x48, 0x00, 0x6a, 0x01, 0x23, -0xdb, 0x03, 0x98, 0x43, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x0a, 0x48, -0xc1, 0x68, 0x01, 0x29, 0x06, 0xd1, 0x80, 0x23, 0xc1, 0x6f, 0x19, 0x43, -0xc1, 0x67, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47, -0x59, 0xcd, 0x21, 0x40, 0x61, 0xa1, 0x21, 0x40, 0xc0, 0x00, 0x18, 0x40, -0xc0, 0x00, 0x18, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, -0x00, 0xb5, 0x10, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x06, 0xd1, 0x80, 0x23, -0xc1, 0x6f, 0x99, 0x43, 0xc1, 0x67, 0x0d, 0x48, 0xc0, 0x46, 0x01, 0x60, -0x0c, 0x4b, 0x0d, 0x48, 0x0d, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xb9, 0xf8, -0x0c, 0x48, 0x41, 0x8d, 0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, -0x0a, 0x48, 0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x09, 0x49, -0xc0, 0x46, 0x08, 0x62, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, -0x00, 0x01, 0x11, 0x00, 0xf1, 0xcc, 0x21, 0x40, 0x61, 0xa1, 0x21, 0x40, +0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, +0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfc, 0xf7, 0x3a, 0xfd, 0x0b, 0x48, +0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46, +0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f, +0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47, +0x8d, 0xd5, 0x21, 0x40, 0xc1, 0xa8, 0x21, 0x40, 0xc0, 0x00, 0x18, 0x40, +0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x0f, 0x48, +0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68, +0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48, 0x0c, 0x4a, 0x00, 0x21, +0xfc, 0xf7, 0x0f, 0xfd, 0x0b, 0x48, 0x41, 0x8d, 0x01, 0x31, 0x41, 0x85, +0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, +0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x25, 0xd5, 0x21, 0x40, 0xc1, 0xa8, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, -0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0xfe, 0xf7, 0xa3, 0xfe, 0x19, 0x4c, -0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x60, 0x88, 0x00, 0x28, -0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67, 0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, -0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18, 0xc1, 0x43, 0xa8, 0x61, 0x29, 0x62, -0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03, 0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, -0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x70, 0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, -0xb8, 0x60, 0x00, 0xf0, 0x47, 0xfa, 0x00, 0xf0, 0xd9, 0xfa, 0x04, 0x20, -0xb8, 0x60, 0x07, 0x20, 0x78, 0x61, 0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, -0xe0, 0x18, 0x40, 0x8b, 0x04, 0x23, 0x18, 0x40, 0xa8, 0x62, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb4, 0x02, 0x1c, -0x00, 0x20, 0xff, 0x23, 0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, -0x00, 0xd1, 0x01, 0x20, 0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, -0x80, 0xbc, 0x70, 0x47, 0x18, 0x49, 0xca, 0x68, 0x18, 0x4b, 0x01, 0x2a, -0x0b, 0xd1, 0x4a, 0x88, 0x00, 0x2a, 0x08, 0xd1, 0xd9, 0x8a, 0x0a, 0x09, -0x00, 0xd3, 0x02, 0x20, 0x49, 0x09, 0xef, 0xd3, 0x01, 0x23, 0x18, 0x43, -0xec, 0xe7, 0x0a, 0x79, 0x00, 0x2a, 0x03, 0xd0, 0x18, 0x8a, 0x80, 0x07, -0x80, 0x0f, 0xe5, 0xe7, 0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x0a, 0x88, -0xff, 0x27, 0x01, 0x37, 0x17, 0x40, 0x0b, 0x49, 0x49, 0x88, 0x03, 0xd0, -0x4b, 0x0a, 0x01, 0xd3, 0x03, 0x20, 0xd7, 0xe7, 0x13, 0x0a, 0x03, 0xd3, -0x0b, 0x0a, 0x01, 0xd3, 0x02, 0x20, 0xd1, 0xe7, 0xd2, 0x09, 0xcf, 0xd3, -0xc9, 0x09, 0xcd, 0xd3, 0x01, 0x20, 0xcb, 0xe7, 0xe8, 0x0d, 0x00, 0x80, -0xa8, 0x1b, 0x00, 0x80, 0x88, 0x1b, 0x00, 0x80, 0xf0, 0xb5, 0xc1, 0xb0, -0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x52, 0x48, -0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03, 0x48, 0x60, 0x50, 0x48, -0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21, 0x03, 0x03, 0x1b, 0x0b, -0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b, +0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0xfe, 0xf7, 0x9b, 0xfe, 0x1b, 0x4c, +0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28, +0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67, +0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18, +0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03, +0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71, +0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa, +0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61, +0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23, +0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23, +0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20, +0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47, +0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23, +0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f, +0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3, +0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7, +0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7, +0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37, +0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3, +0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3, +0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3, +0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80, +0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46, +0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03, +0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21, +0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b, 0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33, -0xdb, 0x69, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43, -0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07, -0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30, -0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03, -0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03, -0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62, -0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a, 0x01, 0x33, 0x23, 0x62, -0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34, 0x5c, 0x65, 0x00, 0x29, -0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c, 0x6b, 0x44, 0x5c, 0x68, -0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42, 0xf5, 0xd1, 0x30, 0x4c, -0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x08, 0xd1, -0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24, 0x2b, 0x4b, 0xc0, 0x46, -0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b, 0x23, 0x4c, 0x51, 0x26, -0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0xfd, 0x69, 0xc0, 0x46, 0x75, 0x61, -0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60, 0x01, 0x25, 0xb5, 0x60, -0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x70, 0x88, 0x42, 0x21, 0xd0, 0x25, 0x1c, -0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f, 0x6b, 0x44, 0x34, 0x60, -0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60, 0x2b, 0x6f, 0x08, 0x33, -0x2b, 0x67, 0xfc, 0x69, 0xa3, 0x42, 0x02, 0xd3, 0x12, 0x4b, 0xc0, 0x46, -0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, -0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03, 0x2b, 0x6f, 0xc0, 0x46, -0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b, 0x03, 0xd3, 0x0e, 0x49, -0x01, 0x20, 0xfc, 0xf7, 0x72, 0xff, 0x41, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x01, 0x14, 0x40, -0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, -0x24, 0xa7, 0x20, 0x40, 0x10, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, -0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x49, 0x4f, 0xff, 0xff, -0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22, 0x06, 0x24, 0x47, 0x4f, -0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33, 0x20, 0x2b, 0xf9, 0xd3, -0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61, 0x3c, 0x61, 0x3a, 0x61, -0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x3f, 0x4d, 0xab, 0x6f, -0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, -0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x9e, 0x08, 0x02, 0x23, +0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43, +0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, +0x01, 0x23, 0x9b, 0x07, 0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, +0x63, 0x60, 0x08, 0x30, 0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, +0x3f, 0x48, 0x03, 0x03, 0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, +0x01, 0x23, 0x1b, 0x03, 0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, +0x01, 0x33, 0x63, 0x62, 0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a, +0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34, +0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c, +0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42, +0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, +0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24, +0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b, +0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a, +0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60, +0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42, +0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f, +0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60, +0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3, +0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44, +0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03, +0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b, +0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfc, 0xf7, 0xc2, 0xfb, 0x41, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, +0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40, +0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, +0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, +0xb5, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22, +0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33, +0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61, +0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61, +0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, +0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, +0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, +0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, -0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, -0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x02, 0x23, -0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, -0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00, 0x02, 0x23, 0x1d, 0x40, -0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, -0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, -0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40, -0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, +0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, +0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00, +0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, +0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, +0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08, +0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25, -0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, -0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43, -0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61, -0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61, -0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40, -0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30, 0x10, 0x28, 0xf2, 0xd3, -0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61, 0x3c, 0x61, 0x3a, 0x61, -0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08, 0xf0, 0xbc, 0x70, 0x47, -0x80, 0x00, 0x14, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0x00, 0x14, 0x40, -0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27, 0x44, 0x4a, 0xc0, 0x46, -0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c, 0xf9, 0xd3, 0x04, 0x26, -0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, -0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61, 0x3c, 0x4b, 0x9b, 0x6f, -0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, -0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f, 0x9d, 0x08, 0x02, 0x23, +0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, +0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, +0x04, 0x23, 0x03, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, +0x00, 0x25, 0x3d, 0x61, 0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, +0x00, 0x20, 0x3d, 0x61, 0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, +0x02, 0x23, 0x33, 0x40, 0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30, +0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61, +0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08, +0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, +0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27, +0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c, +0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61, +0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61, +0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, +0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f, +0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, +0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, -0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, -0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x2d, 0x4b, 0x9d, 0x6f, +0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, +0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, -0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00, 0x02, 0x23, 0x1d, 0x40, -0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0xc5, 0x08, +0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, +0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40, +0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, -0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, -0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, -0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x02, 0x25, -0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, -0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c, 0x33, 0x43, 0x13, 0x61, -0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x16, 0x61, -0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21, 0x25, 0x1c, 0xcd, 0x40, -0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x05, 0x23, -0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39, 0x10, 0x28, 0xf1, 0xd3, -0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61, 0x13, 0x61, 0x03, 0x20, -0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x00, -0xe8, 0x0d, 0x00, 0x80, 0xf0, 0xb5, 0x47, 0x48, 0x01, 0x89, 0x47, 0x4d, -0x07, 0x23, 0x5b, 0x02, 0xef, 0x18, 0xb9, 0x83, 0x40, 0x8b, 0xc0, 0x46, -0xf8, 0x83, 0x28, 0x79, 0x00, 0x28, 0x01, 0xd0, 0x00, 0x20, 0xb8, 0x83, -0xe8, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x68, 0x88, 0x00, 0x28, 0x03, 0xd1, -0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x54, 0xff, 0x01, 0x21, 0xc9, 0x03, -0x00, 0x20, 0xff, 0xf7, 0x4f, 0xff, 0x00, 0x24, 0x7d, 0x26, 0xf6, 0x00, -0x00, 0xe0, 0x01, 0x34, 0x00, 0x20, 0xff, 0xf7, 0xad, 0xfe, 0x00, 0x0c, -0x01, 0xd3, 0xb4, 0x42, 0xf7, 0xd3, 0x00, 0x24, -0x05, 0xe0, 0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3c, 0xff, -0x01, 0x34, 0x00, 0x20, 0xff, 0xf7, 0x9e, 0xfe, 0x40, 0x0b, 0x01, 0xd2, -0xb4, 0x42, 0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x97, 0xfe, 0xff, 0x23, -0xe1, 0x33, 0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0xb8, 0x8b, 0xff, 0x23, -0x01, 0x33, 0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01, 0x19, 0x43, -0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0xf8, 0x8b, 0x01, 0x28, 0x03, 0xd1, -0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23, 0x19, 0x43, -0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0xf8, 0x8b, 0x01, 0x28, 0x03, 0xd1, -0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, -0x04, 0x20, 0xff, 0xf7, 0x09, 0xff, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, -0xff, 0xf7, 0x04, 0xff, 0xe8, 0x68, 0x00, 0x28, 0x0c, 0xd1, 0x00, 0x21, -0x1b, 0x20, 0xff, 0xf7, 0xfd, 0xfe, 0x1a, 0x20, 0xff, 0xf7, 0x60, 0xfe, -0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7, 0xf4, 0xfe, -0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f, 0x08, 0xd9, -0x38, 0x1c, 0xff, 0xf7, 0x51, 0xfe, 0x79, 0x00, 0x49, 0x19, 0x1b, 0x23, -0xdb, 0x01, 0xc9, 0x18, 0x08, 0x83, 0x01, 0x37, 0x20, 0x2f, 0xef, 0xd3, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x70, 0x67, 0x21, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x81, 0xb0, 0x13, 0x48, 0x01, 0x68, 0xc0, 0x46, -0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x68, 0xc0, 0x46, -0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x01, 0x69, 0xc0, 0x46, -0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x69, 0xc0, 0x46, -0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x01, 0x6a, 0xc0, 0x46, -0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x6a, 0xc0, 0x46, -0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x01, 0xb0, 0x70, 0x47, -0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0, 0x66, 0x4e, 0x1b, 0x23, -0xdb, 0x01, 0xf7, 0x18, 0x78, 0x8b, 0x04, 0x22, 0x02, 0x40, 0x02, 0x92, -0x07, 0x23, 0x5b, 0x02, 0xf4, 0x18, 0xa0, 0x8b, 0xc0, 0x46, 0x01, 0x90, -0xe0, 0x8b, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x25, 0x03, 0xe0, 0x08, 0x2d, -0x01, 0xd3, 0x0f, 0x2d, 0x08, 0xd9, 0x28, 0x1c, 0xff, 0xf7, 0xfa, 0xfd, -0x69, 0x00, 0x89, 0x19, 0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x08, 0x83, -0x01, 0x35, 0x20, 0x2d, 0xef, 0xd3, 0xa0, 0x69, 0x00, 0x28, 0x15, 0xd0, -0x54, 0x4e, 0x20, 0x25, 0x01, 0x3d, 0x52, 0x49, 0xa0, 0x69, 0x30, 0x40, -0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18, 0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, -0x01, 0x8b, 0x28, 0x1c, 0xff, 0xf7, 0x78, 0xfe, 0xa0, 0x69, 0xb0, 0x43, -0xa0, 0x61, 0x76, 0x08, 0x00, 0x2d, 0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, -0xd5, 0xfd, 0x01, 0x1c, 0x46, 0x48, 0xc0, 0x46, 0x79, 0x83, 0x79, 0x8b, -0xca, 0x08, 0x22, 0xd3, 0xc2, 0x68, 0x01, 0x2a, 0x10, 0xd1, 0x40, 0x88, -0x00, 0x28, 0x1c, 0xd1, 0x01, 0x98, 0x42, 0x4a, 0x00, 0x28, 0x05, 0xd0, -0x01, 0x28, 0x16, 0xd1, 0xd0, 0x8a, 0xc0, 0x08, 0x13, 0xd2, 0x0f, 0xe0, -0xd0, 0x8a, 0x00, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x02, 0x79, 0x00, 0x2a, -0x0b, 0xd1, 0x6d, 0x23, 0x5b, 0x01, 0xc0, 0x18, 0x02, 0x88, 0x40, 0x88, -0x10, 0x40, 0x40, 0x09, 0x00, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x99, 0x43, -0x79, 0x83, 0x78, 0x8b, 0x04, 0x21, 0x01, 0x40, -0x02, 0x9a, 0x1f, 0xd0, 0x39, 0x8b, 0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, -0x25, 0xd3, 0xff, 0x23, 0x01, 0x98, 0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, -0x00, 0x25, 0x00, 0x98, 0x01, 0x28, 0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, -0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, -0x13, 0xd0, 0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x25, 0xfe, 0x3d, 0x83, -0x00, 0x20, 0xc0, 0x43, 0x20, 0x62, 0x0a, 0xe0, 0x38, 0x8b, 0x40, 0x0b, -0x07, 0xd2, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x18, 0xfe, -0x09, 0x20, 0x40, 0x02, 0x38, 0x83, 0x78, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, -0x1b, 0x48, 0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x6a, 0xfc, -0xc2, 0x07, 0xd2, 0x0f, 0x18, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, -0x2b, 0x43, 0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, -0xcb, 0x65, 0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, -0x03, 0xe0, 0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, -0x21, 0x6a, 0x81, 0x42, 0x0c, 0xd0, 0x20, 0x62, 0x0c, 0x48, 0x00, 0x2a, -0x03, 0xd0, 0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, -0x21, 0x33, 0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, -0xa8, 0x1b, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40, 0x10, 0x2a, 0x00, 0x80, -0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22, 0x20, 0x28, 0x0f, 0xd2, -0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18, 0x37, 0x23, 0x9b, 0x01, -0xe3, 0x18, 0x1f, 0x83, 0x82, 0x40, 0x07, 0x23, 0x5b, 0x02, 0xc9, 0x18, -0x10, 0x1c, 0x8a, 0x69, 0x10, 0x43, 0x88, 0x61, 0x90, 0xbc, 0x70, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69, 0x0b, 0x49, 0x49, 0x8b, -0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0, 0x01, 0x23, 0xdb, 0x02, -0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43, 0x05, 0xe0, 0x01, 0x23, -0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08, 0x52, 0x00, 0xca, 0x65, -0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, 0x68, 0x1b, 0x00, 0x80, -0x10, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xff, 0xf7, 0xde, 0xff, -0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20, 0x01, 0xab, 0x18, 0x80, -0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab, 0x5a, 0x80, 0xd9, 0x80, -0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91, 0x03, 0x90, 0x68, 0x46, -0x00, 0x21, 0xfc, 0xf7, 0x9d, 0xfd, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, -0x10, 0x2a, 0x00, 0x80, 0x0d, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, -0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, -0x09, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, 0x08, 0x48, 0x80, 0x6c, -0x00, 0x04, 0x00, 0x0c, 0x07, 0x4b, 0x98, 0x42, 0x02, 0xd0, 0x02, 0x33, -0x98, 0x42, 0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, +0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, +0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c, +0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23, +0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21, +0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, +0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39, +0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61, +0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, +0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d, +0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfc, 0xf7, 0x75, 0xfa, 0x4d, 0x4c, +0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20, +0x2a, 0x1c, 0xfc, 0xf7, 0x6b, 0xfa, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28, +0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1, +0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02, +0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28, +0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21, +0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26, +0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe, +0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, +0x00, 0x25, 0x05, 0xe0, 0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, +0x2b, 0xff, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, +0x01, 0xd2, 0xb5, 0x42, 0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, +0xff, 0x23, 0xe1, 0x33, 0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, +0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01, +0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28, +0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23, +0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28, +0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, +0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02, +0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1, +0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7, +0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7, +0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f, +0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19, +0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f, +0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0xbf, 0x21, 0x40, +0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48, +0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91, +0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91, +0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91, +0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91, +0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91, +0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90, +0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0, +0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22, +0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88, +0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24, +0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c, +0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01, +0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c, +0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d, +0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18, +0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7, +0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d, +0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46, +0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a, +0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29, +0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29, +0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b, +0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1, +0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40, +0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, +0x98, 0x43, 0xf8, 0x83, 0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, +0x1f, 0xd0, 0xb9, 0x8b, 0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, +0xff, 0x23, 0x01, 0x98, 0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, +0x00, 0x98, 0x01, 0x28, 0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, +0x02, 0xd1, 0x01, 0x23, 0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0, +0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20, +0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2, +0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20, +0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48, +0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07, +0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43, +0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, +0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0, +0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a, +0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0, +0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33, +0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80, +0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40, +0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22, +0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18, +0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23, +0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61, +0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69, +0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0, +0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43, +0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08, +0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, +0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, +0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20, +0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab, +0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91, +0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfc, 0xf7, 0xd5, 0xf9, 0x04, 0xb0, +0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68, +0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, +0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, +0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42, +0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42, +0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, -0x04, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24, 0x21, 0x1c, 0x17, 0x48, -0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x02, 0xd1, -0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21, 0x09, 0x06, 0x09, 0x0e, -0x11, 0x4f, 0x12, 0x4a, 0x02, 0xd0, 0x38, 0x68, 0x00, 0x0c, 0x00, 0xe0, -0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x0f, 0x4b, -0x98, 0x42, 0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x0d, 0x4b, -0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29, 0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, -0x00, 0xe0, 0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, -0x00, 0x0e, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, -0x04, 0x99, 0x00, 0x00, 0x05, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, -0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, -0x80, 0x0a, 0x02, 0xd3, 0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, -0x40, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, -0x40, 0x08, 0x01, 0xd3, 0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, -0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, -0xf0, 0xb5, 0x01, 0x27, 0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x7a, 0xff, -0x03, 0x1c, 0x19, 0x4a, 0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, -0x1b, 0xd1, 0xcb, 0x04, 0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, -0x43, 0x60, 0x06, 0x68, 0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, -0x43, 0x60, 0x03, 0x68, 0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, -0x05, 0x23, 0x0f, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, -0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, -0x23, 0x60, 0x04, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, -0x06, 0x60, 0x27, 0x68, 0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, -0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, -0x00, 0x00, 0x28, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x38, 0xff, -0x01, 0x28, 0x05, 0xd1, 0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, -0x08, 0x40, 0x22, 0xe0, 0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, -0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, -0x14, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, -0x00, 0x04, 0x00, 0x0c, 0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, -0x01, 0xa3, 0x1b, 0x5c, 0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, -0x07, 0x07, 0x05, 0x03, 0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, -0x00, 0x20, 0x01, 0x21, 0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, -0x08, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x98, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, -0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, -0xf0, 0xb5, 0x83, 0xb0, 0x07, 0x1c, 0x01, 0x20, 0x02, 0x90, 0x01, 0x25, -0x02, 0x24, 0x10, 0x26, 0x20, 0x21, 0x00, 0x91, 0xff, 0xf7, 0xea, 0xfe, -0x01, 0x28, 0x4d, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x3a, 0xd1, -0x2e, 0x4e, 0x3c, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 0x1c, 0xfb, -0x3e, 0x21, 0x05, 0x1c, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 0x16, 0xfb, -0x00, 0x04, 0x05, 0x43, 0x40, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, -0x0f, 0xfb, 0x01, 0x90, 0x42, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, -0x09, 0xfb, 0x00, 0x04, 0x01, 0x99, 0x08, 0x43, 0x06, 0x1c, 0xa8, 0x2f, -0x1b, 0xd1, 0x1f, 0x4a, 0x44, 0x21, 0x02, 0x20, -0xfc, 0xf7, 0xfe, 0xfa, 0x04, 0x1c, 0x1c, 0x4a, 0x46, 0x21, 0x02, 0x20, -0xfc, 0xf7, 0xf8, 0xfa, 0x00, 0x04, 0x04, 0x43, 0x18, 0x4a, 0x48, 0x21, -0x02, 0x20, 0xfc, 0xf7, 0xf1, 0xfa, 0x00, 0x90, 0x15, 0x4a, 0x4a, 0x21, -0x02, 0x20, 0xfc, 0xf7, 0xeb, 0xfa, 0x00, 0x04, 0x00, 0x99, 0x01, 0x43, -0x00, 0x91, 0x28, 0x1c, 0x30, 0x43, 0x20, 0x43, 0x00, 0x99, 0x08, 0x43, -0x00, 0xd1, 0x16, 0xe0, 0x11, 0x20, 0x00, 0x04, 0x05, 0x62, 0x46, 0x62, -0x84, 0x62, 0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x0a, 0x48, -0xc0, 0x46, 0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, -0x01, 0x21, 0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, -0x02, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x39, 0xb7, 0x21, 0x40, 0x98, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x07, 0x1c, -0xff, 0xf7, 0x7e, 0xfe, 0x01, 0x28, 0x19, 0xd1, 0x01, 0x05, 0x11, 0x48, -0x00, 0x2f, 0x18, 0xd0, 0x0b, 0x0a, 0x02, 0x68, 0x9a, 0x43, 0x0a, 0x60, -0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x0b, 0xd1, -0x00, 0x68, 0x80, 0x0a, 0x08, 0xd3, 0x0a, 0x48, 0x40, 0x6a, 0xff, 0x22, -0x01, 0x32, 0x02, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x4a, 0x62, 0x48, 0x62, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x68, 0x01, 0x23, 0x1b, 0x03, -0x18, 0x43, 0x08, 0x60, 0xf6, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, -0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x70, 0x47, 0x00, 0x00, +0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24, +0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68, +0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, +0x00, 0xd2, 0x00, 0x21, 0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, +0x02, 0xd0, 0x38, 0x68, 0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, +0x00, 0x0c, 0x10, 0x4b, 0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, +0x05, 0xd0, 0x0e, 0x4b, 0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, +0x0c, 0xd1, 0x00, 0x29, 0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0, +0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e, +0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40, +0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00, +0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, +0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3, +0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04, +0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3, +0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40, +0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27, +0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a, +0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04, +0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68, +0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68, +0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f, +0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60, +0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23, +0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68, +0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40, +0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40, +0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1, +0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0, +0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, +0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68, +0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, +0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c, +0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03, +0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21, +0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e, +0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x98, 0x6e, 0x21, 0x40, +0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, +0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x83, 0xb0, +0x07, 0x1c, 0x01, 0x20, 0x02, 0x90, 0x01, 0x25, 0x02, 0x24, 0x10, 0x26, +0x20, 0x21, 0x00, 0x91, 0xff, 0xf7, 0xe2, 0xfe, 0x01, 0x28, 0x4d, 0xd1, +0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x3a, 0xd1, 0x2e, 0x4e, 0x3c, 0x21, +0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 0x4c, 0xff, 0x3e, 0x21, 0x05, 0x1c, +0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, 0x46, 0xff, 0x00, 0x04, 0x05, 0x43, +0x40, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, +0x3f, 0xff, 0x01, 0x90, 0x42, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfb, 0xf7, +0x39, 0xff, 0x00, 0x04, 0x01, 0x99, 0x08, 0x43, 0x06, 0x1c, 0xa8, 0x2f, +0x1b, 0xd1, 0x1f, 0x4a, 0x44, 0x21, 0x02, 0x20, 0xfb, 0xf7, 0x2e, 0xff, +0x04, 0x1c, 0x1c, 0x4a, 0x46, 0x21, 0x02, 0x20, 0xfb, 0xf7, 0x28, 0xff, +0x00, 0x04, 0x04, 0x43, 0x18, 0x4a, 0x48, 0x21, 0x02, 0x20, 0xfb, 0xf7, +0x21, 0xff, 0x00, 0x90, 0x15, 0x4a, 0x4a, 0x21, 0x02, 0x20, 0xfb, 0xf7, +0x1b, 0xff, 0x00, 0x04, 0x00, 0x99, 0x01, 0x43, 0x00, 0x91, 0x28, 0x1c, +0x30, 0x43, 0x20, 0x43, 0x00, 0x99, 0x08, 0x43, 0x00, 0xd1, 0x16, 0xe0, +0x11, 0x20, 0x00, 0x04, 0x05, 0x62, 0x46, 0x62, 0x84, 0x62, 0x00, 0x99, +0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x0a, 0x48, 0xc0, 0x46, 0x01, 0x60, +0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21, 0x01, 0x60, +0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x02, 0x98, 0x03, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x79, 0xbf, 0x21, 0x40, +0x98, 0x6e, 0x21, 0x40, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, -0x0b, 0xd0, 0x00, 0x23, 0x21, 0x1c, 0xe2, 0x1d, 0x6d, 0x32, 0x00, 0xe0, -0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0x74, 0x20, 0xa0, 0x80, +0x0b, 0xd0, 0x00, 0x23, 0x21, 0x1c, 0xe2, 0x1d, 0xc5, 0x32, 0x00, 0xe0, +0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xcc, 0x20, 0xa0, 0x80, 0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48, -0xc0, 0x46, 0xe0, 0x60, 0x08, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19, +0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19, 0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80, 0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80, -0xfe, 0xca, 0x01, 0x20, 0x17, 0x40, 0x00, 0x02, 0x80, 0xb4, 0x08, 0x4a, -0xd1, 0x1d, 0x49, 0x31, 0x0b, 0x78, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23, -0x0b, 0x70, 0x07, 0x1c, 0x08, 0x78, 0x43, 0x1c, 0x0b, 0x70, 0x80, 0x18, -0x50, 0x30, 0x47, 0x70, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80, +0xee, 0xff, 0xc0, 0xd0, 0x02, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a, +0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7b, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23, +0x0b, 0x73, 0x07, 0x1c, 0x08, 0x7b, 0x43, 0x1c, 0x0b, 0x73, 0x80, 0x18, +0x90, 0x30, 0x47, 0x73, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80, 0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20, 0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7, -0x4d, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42, -0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7, -0x81, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xbc, 0x67, 0x21, 0x40, +0xab, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42, +0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfb, 0xf7, +0xdf, 0xff, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x67, 0x21, 0x40, 0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c, 0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89, 0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c, 0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c, 0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e, -0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, -0x79, 0x6c, 0x59, 0x43, 0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, -0x01, 0x32, 0x12, 0x04, 0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, -0x23, 0x80, 0x00, 0x22, 0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, -0x5e, 0x4b, 0x1d, 0x88, 0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, -0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, +0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43, +0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04, +0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22, +0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88, +0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23, +0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49, 0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81, 0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20, 0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, -0x65, 0xfa, 0xf0, 0x88, 0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, +0x8d, 0xfa, 0xf0, 0x88, 0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04, 0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80, 0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0, 0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, @@ -3446,9 +3614,9 @@ 0xdb, 0x03, 0x78, 0x6c, 0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0, 0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, -0x4b, 0xfa, 0xe0, 0x6a, 0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, +0x79, 0xfa, 0xe0, 0x6a, 0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39, 0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, -0xc5, 0xfa, 0xb6, 0xe7, 0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04, +0xf3, 0xfa, 0xb6, 0xe7, 0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04, 0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80, 0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b, 0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d, @@ -3456,193 +3624,208 @@ 0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30, 0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19, -0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xfa, 0x71, 0x88, +0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfa, 0x71, 0x88, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0, -0x89, 0xfa, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35, +0xb7, 0xfa, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35, 0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xb8, 0x2a, 0x00, 0x80, 0xc8, 0x29, 0x00, 0x80, -0xbc, 0x67, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03, -0x33, 0x40, 0x01, 0x24, 0x30, 0x4f, 0x00, 0x20, 0x30, 0x4a, 0x31, 0x4d, -0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x2f, 0xd0, 0xe3, 0x03, 0xf3, 0x1a, -0x51, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x4e, 0xd3, 0xee, 0x88, 0x00, 0x2e, -0x4b, 0xd0, 0xee, 0x6a, 0x5d, 0x1e, 0x6b, 0x00, 0x5d, 0x19, 0x6d, 0x01, -0x73, 0x19, 0x9e, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0, -0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x33, 0x9b, 0x8b, 0x9b, 0x00, -0x21, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0xf0, 0x50, -0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x1e, 0x4e, 0xf2, 0x6a, 0x52, 0x19, -0x90, 0x60, 0xf0, 0x88, 0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, -0x88, 0x81, 0x19, 0x49, 0x00, 0x28, 0x23, 0xd1, 0x4f, 0x80, 0x21, 0xe0, -0x00, 0x2e, 0x22, 0xd9, 0xab, 0x89, 0xb3, 0x42, 0x1f, 0xd3, 0xab, 0x88, -0x00, 0x2b, 0x1c, 0xd0, 0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x58, 0x23, -0x01, 0x3e, 0x73, 0x43, 0xaa, 0x6a, 0xd2, 0x18, 0x93, 0x68, 0x1b, 0x06, -0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0, 0xcb, 0x89, 0x01, 0x33, 0xcb, 0x81, -0x90, 0x60, 0xa8, 0x88, 0x01, 0x38, 0xa8, 0x80, 0xa8, 0x88, 0xc0, 0x46, -0x48, 0x81, 0x00, 0x28, 0x00, 0xd1, 0x2f, 0x80, 0x20, 0x1c, 0xf0, 0xbc, -0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81, 0xf9, 0xe7, 0x00, 0x00, -0xff, 0xff, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0xc8, 0x29, 0x00, 0x80, -0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49, 0x4a, 0x68, 0x00, 0x2a, -0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0, 0xca, 0x1d, 0x19, 0x32, -0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69, 0x00, 0x2a, 0x0b, 0xd1, -0x88, 0x61, 0x48, 0x61, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, -0x4a, 0x69, 0x00, 0x2a, 0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, -0x8a, 0x69, 0xc0, 0x46, 0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, -0xec, 0x05, 0x00, 0x80, 0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, -0x4c, 0xd0, 0x08, 0x22, 0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, -0xd9, 0x1d, 0xb9, 0x31, 0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, -0xc0, 0x46, 0x0c, 0x61, 0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, -0xc0, 0x46, 0x8c, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, -0xc0, 0x46, 0x0c, 0x63, 0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, -0xc0, 0x46, 0x0c, 0x61, 0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, -0xc0, 0x46, 0x8c, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, -0xc0, 0x46, 0x0c, 0x63, 0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, -0xcc, 0x82, 0x4f, 0x83, 0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, -0x8c, 0x00, 0x05, 0x19, 0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, -0x01, 0x34, 0x65, 0x62, 0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, -0x07, 0xd2, 0x8a, 0x00, 0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, -0x01, 0x31, 0x10, 0x29, 0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, -0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, -0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, -0x20, 0x01, 0x40, 0x00, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, -0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, -0x36, 0x36, 0x36, 0x36, 0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, -0x15, 0x4d, 0xe9, 0x1d, 0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, -0x00, 0x20, 0xfc, 0xf7, 0x1a, 0xf8, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, -0x23, 0x1c, 0x0d, 0x1c, 0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x11, 0xf8, -0x29, 0x1c, 0x23, 0x1c, 0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x0b, 0xf8, -0x39, 0x1c, 0x23, 0x1c, 0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x05, 0xf8, -0x00, 0x21, 0x0b, 0x48, 0xc2, 0x1d, 0x19, 0x32, -0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x08, 0x1c, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x1c, 0xad, 0x20, 0x40, -0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00, 0x40, 0x00, 0x02, 0x00, -0x14, 0x00, 0x07, 0x00, 0xec, 0x05, 0x00, 0x80, 0xf0, 0xb5, 0x37, 0x4a, -0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, -0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29, 0x49, 0xd1, 0x1f, 0x68, -0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1, 0xff, 0xf7, 0x3e, 0xff, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23, 0x9f, 0x00, 0xcc, 0x59, -0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, -0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43, 0x53, 0x69, 0xc0, 0x46, -0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68, 0x13, 0x40, 0x25, 0x4f, -0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0, 0x04, 0x23, 0x23, 0x4c, -0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46, 0x14, 0x61, 0x40, 0x24, -0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c, 0x00, 0x22, 0x00, 0x2b, -0x0c, 0xd9, 0x95, 0x00, 0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, -0xff, 0x35, 0x01, 0x35, 0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, -0x10, 0x2a, 0x07, 0xd2, 0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, -0x5c, 0x62, 0x01, 0x32, 0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, -0xbc, 0xe7, 0x00, 0x21, 0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, -0x7c, 0x62, 0x01, 0x31, 0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, -0x03, 0x23, 0x18, 0x43, 0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, -0x40, 0x68, 0xc0, 0x46, 0x50, 0x61, 0x09, 0x48, 0xfb, 0xf7, 0x7a, 0xff, -0xa4, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, -0x67, 0x45, 0x23, 0x01, 0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, -0x20, 0x01, 0x40, 0x00, 0x5c, 0x5c, 0x5c, 0x5c, 0x85, 0x30, 0xff, 0xff, -0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0xb9, 0x6b, -0x0b, 0x48, 0xc2, 0x68, 0x12, 0x04, 0x51, 0x40, 0x82, 0x69, 0x51, 0x40, -0x39, 0x65, 0xf9, 0x6b, 0x82, 0x69, 0x12, 0x04, 0xd2, 0x43, 0x51, 0x40, -0xc0, 0x68, 0xc0, 0x43, 0x48, 0x40, 0x78, 0x65, 0x04, 0x48, 0x01, 0x89, -0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0x08, 0x83, 0x20, 0x40, 0x78, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, -0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68, -0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, -0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, -0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69, -0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, -0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18, -0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08, -0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b, +0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, +0x70, 0x67, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03, +0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d, +0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a, +0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e, +0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01, +0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0, +0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00, +0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35, +0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a, +0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a, +0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a, +0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88, +0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, +0x88, 0x81, 0x24, 0x49, 0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, +0x00, 0x2e, 0x38, 0xd9, 0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, +0x00, 0x2b, 0x2c, 0xd0, 0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, +0xad, 0x6a, 0x58, 0x23, 0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, +0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, +0xce, 0x81, 0xa8, 0x60, 0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, +0xed, 0x18, 0xe8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, +0xed, 0x18, 0x68, 0x64, 0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, +0xeb, 0x18, 0xd8, 0x64, 0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, +0xc0, 0x46, 0x48, 0x81, 0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, +0x03, 0xe0, 0x17, 0x80, 0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, +0x01, 0x32, 0xca, 0x81, 0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, +0x0c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, +0x41, 0x60, 0x10, 0x49, 0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, +0x00, 0x2a, 0x04, 0xd0, 0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, +0x08, 0xd0, 0x4a, 0x69, 0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61, +0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a, +0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46, +0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, +0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22, +0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31, +0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61, +0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62, +0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63, +0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61, +0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62, +0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63, +0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83, +0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19, +0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62, +0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00, +0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29, +0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, +0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, +0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00, +0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe, +0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36, +0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d, +0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfb, 0xf7, +0x50, 0xfc, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c, +0x11, 0x4a, 0x01, 0x20, 0xfb, 0xf7, 0x47, 0xfc, 0x29, 0x1c, 0x23, 0x1c, +0x0e, 0x4a, 0x00, 0x20, 0xfb, 0xf7, 0x41, 0xfc, +0x39, 0x1c, 0x23, 0x1c, 0x0c, 0x4a, 0x01, 0x20, 0xfb, 0xf7, 0x3b, 0xfc, +0x00, 0x21, 0x0b, 0x48, 0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, +0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x1c, 0xad, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, +0x28, 0x00, 0x03, 0x00, 0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, +0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, +0x9b, 0x07, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, +0x33, 0x4b, 0x01, 0x29, 0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, +0x9f, 0x42, 0x04, 0xd1, 0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x23, 0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, +0x3c, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, +0x02, 0x23, 0x18, 0x43, 0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, +0x08, 0x23, 0xc2, 0x68, 0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, +0x00, 0x2b, 0x02, 0xd0, 0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, +0x22, 0x4c, 0xc0, 0x46, 0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, +0x54, 0x83, 0x20, 0x4c, 0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00, +0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35, +0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2, +0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32, +0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21, +0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31, +0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43, +0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46, +0x50, 0x61, 0x09, 0x48, 0xfb, 0xf7, 0xb0, 0xfb, 0xa4, 0xe7, 0x00, 0x00, +0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01, +0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00, +0x5c, 0x5c, 0x5c, 0x5c, 0xfd, 0x30, 0xff, 0xff, 0x80, 0xb5, 0x87, 0xb0, +0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x48, 0xf8, 0x0e, 0x49, 0xc8, 0x68, +0x02, 0x04, 0x89, 0x69, 0x4a, 0x40, 0x05, 0x92, 0x09, 0x04, 0xc9, 0x43, +0xc0, 0x43, 0x48, 0x40, 0x06, 0x90, 0x08, 0x21, 0x6a, 0x46, 0x05, 0xa8, +0xfd, 0xf7, 0x8b, 0xfb, 0x00, 0x98, 0xc0, 0x46, 0x38, 0x65, 0x03, 0x98, +0xc0, 0x46, 0x78, 0x65, 0x04, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, +0x07, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x83, 0x20, 0x40, +0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x20, 0x1c, +0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68, 0x01, 0x0e, 0xff, 0x22, +0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, +0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x65, +0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69, 0xc0, 0x46, 0xb8, 0x65, +0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x22, +0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18, 0x5f, 0x62, 0x01, 0x32, +0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08, 0x03, 0xd3, 0x00, 0x23, +0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b, 0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b, 0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c, -0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, -0xca, 0x64, 0xc2, 0x88, 0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, -0x03, 0x7a, 0x1b, 0x04, 0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, -0x43, 0x7a, 0xdb, 0x07, 0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, -0x5a, 0x08, 0x05, 0xd3, 0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, -0x15, 0x22, 0x00, 0xe0, 0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, -0xc0, 0x08, 0x02, 0xd3, 0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, -0x10, 0x43, 0x3a, 0x0a, 0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, -0x8a, 0x60, 0x08, 0x1c, 0xff, 0xf7, 0x14, 0xfe, 0x05, 0xe0, 0x38, 0x0a, -0x00, 0x02, 0x03, 0x23, 0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, -0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x78, 0x2a, 0x00, 0x80, 0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, -0xe7, 0x69, 0xbd, 0x40, 0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, -0x2e, 0x1c, 0x45, 0x6d, 0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, -0xfd, 0x40, 0x2f, 0x1c, 0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, -0x08, 0xd0, 0x23, 0x69, 0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, -0xbe, 0x00, 0xae, 0x59, 0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, -0x11, 0x43, 0x05, 0x4b, 0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, -0x87, 0x83, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xc8, 0x29, 0x00, 0x80, -0x00, 0x00, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x00, 0xf0, -0xb1, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0x0e, 0xfa, 0x38, 0x0c, 0x00, 0xf0, -0x0b, 0xfa, 0x38, 0x0a, 0x00, 0xf0, 0x08, 0xfa, 0x38, 0x1c, 0x00, 0xf0, -0x05, 0xfa, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, -0x00, 0xf0, 0x9e, 0xfa, 0x54, 0x20, 0x00, 0xf0, 0xfb, 0xf9, 0x38, 0x0c, -0x00, 0xf0, 0xf8, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xf5, 0xf9, 0x38, 0x1c, -0x00, 0xf0, 0xf2, 0xf9, 0x00, 0x20, 0x00, 0xf0, 0xef, 0xf9, 0x80, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 0x89, 0xfa, 0x57, 0x20, -0x00, 0xf0, 0xe6, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, -0x41, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xc8, 0xff, 0x00, 0xf0, 0x64, 0xfa, -0x00, 0xf0, 0xf5, 0xf8, 0x00, 0x24, 0x00, 0x26, 0x00, 0x25, 0x00, 0x27, -0x30, 0x1c, 0x01, 0x36, 0xff, 0xf7, 0xd0, 0xff, 0x00, 0xf0, 0x46, 0xf9, -0x00, 0x90, 0x00, 0xf0, 0x55, 0xfa, 0xf8, 0x00, 0x00, 0x99, 0x81, 0x40, -0x0d, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xee, 0xd3, 0x02, 0x99, -0x20, 0xc1, 0x02, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42, 0xe5, 0xd3, -0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x04, 0x1c, -0x0f, 0x1c, 0x00, 0x26, 0x20, 0xcf, 0xb1, 0x00, 0x84, 0x20, 0xff, 0xf7, -0x9b, 0xff, 0x28, 0x1c, 0x00, 0xf0, 0xae, 0xf9, 0x28, 0x0a, 0x00, 0xf0, -0xab, 0xf9, 0x28, 0x0c, 0x00, 0xf0, 0xa8, 0xf9, 0x28, 0x0e, 0x00, 0xf0, -0xa5, 0xf9, 0x00, 0xf0, 0x2b, 0xfa, 0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, -0x61, 0x02, 0x83, 0x20, 0xff, 0xf7, 0x86, 0xff, 0x00, 0xf0, 0x22, 0xfa, -0x00, 0xf0, 0xb3, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, -0x41, 0x02, 0x60, 0x20, 0xff, 0xf7, 0x7a, 0xff, 0x00, 0xf0, 0x16, 0xfa, -0x00, 0xf0, 0xa7, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x90, 0xb5, 0x0f, 0x1c, 0x41, 0x02, 0x53, 0x20, -0xff, 0xf7, 0x6c, 0xff, 0x00, 0xf0, 0x08, 0xfa, 0x00, 0xf0, 0x99, 0xf8, -0xf8, 0x1d, 0x05, 0x30, 0x44, 0x1c, 0xff, 0xf7, 0x77, 0xff, 0x00, 0xf0, -0xed, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0xfc, 0xf9, 0x20, 0x1c, 0xff, 0xf7, -0x6f, 0xff, 0x00, 0xf0, 0xe5, 0xf8, 0x04, 0x1c, 0x00, 0xf0, 0xf4, 0xf9, -0x20, 0x02, 0x38, 0x43, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, -0xc2, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x17, 0x1c, 0x61, 0x02, 0x53, 0x20, -0xff, 0xf7, 0x48, 0xff, 0x00, 0xf0, 0xe4, 0xf9, 0x00, 0xf0, 0x75, 0xf8, -0x68, 0x46, 0x00, 0xf0, 0x5c, 0xf8, 0x6a, 0x46, 0xe8, 0x1d, 0x05, 0x30, -0x17, 0x54, 0x39, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46, 0x00, 0x99, -0x0c, 0x30, 0x00, 0xf0, 0x73, 0xf8, 0x02, 0xab, 0x18, 0x70, 0x00, 0x20, -0x58, 0x70, 0x68, 0x46, 0x0c, 0x21, 0x00, 0xf0, 0x6b, 0xf8, 0x02, 0xab, -0x58, 0x70, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x83, 0xff, 0x42, 0xb0, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0xc2, 0xb0, 0x04, 0x1c, -0x1f, 0x1c, 0x6b, 0x46, 0x00, 0x20, 0xc5, 0x43, 0x20, 0xc3, 0x01, 0x30, -0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30, 0x03, 0x1c, 0x00, 0x25, -0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46, 0x06, 0x70, 0x0e, 0x88, -0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31, 0x02, 0x35, 0x95, 0x42, -0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c, 0x00, 0xf0, 0x40, 0xf8, -0x00, 0x26, 0x01, 0x96, 0x02, 0xab, 0x18, 0x70, 0x5e, 0x70, 0x9e, 0x70, -0xde, 0x70, 0x05, 0x1c, 0x68, 0x46, 0x0c, 0x21, 0x00, 0xf0, 0x34, 0xf8, -0x02, 0xab, 0x58, 0x70, 0x38, 0x06, 0x00, 0x0e, 0x85, 0x42, 0x05, 0xd1, -0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x48, 0xff, 0x30, 0x1c, 0x00, 0xe0, -0x01, 0x20, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, -0x07, 0x1c, 0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0xff, 0xf7, -0xf1, 0xfe, 0x00, 0xf0, 0x67, 0xf8, 0x05, 0x1c, 0x00, 0xf0, 0x76, 0xf9, -0x3d, 0x70, 0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, -0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0xff, 0xf7, 0xf6, 0xfe, -0x00, 0xf0, 0x56, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0x65, 0xf9, 0x38, 0x0a, -0xf6, 0xd3, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb4, 0x00, 0x22, -0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78, 0x7a, 0x40, 0x01, 0x30, -0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43, 0x00, 0x06, 0x00, 0x0e, -0x80, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02, -0x53, 0x20, 0xff, 0xf7, 0xab, 0xfe, 0x00, 0xf0, 0x47, 0xf9, 0xff, 0xf7, -0xd8, 0xff, 0x68, 0x46, 0xff, 0xf7, 0xbf, 0xff, 0x02, 0xad, 0x6d, 0x78, -0x00, 0x24, 0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, -0xd9, 0xff, 0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, -0x20, 0x1c, 0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x80, 0xb5, 0xc2, 0xb0, 0x69, 0x46, 0x02, 0x20, 0xff, 0xf7, -0xbb, 0xfe, 0x68, 0x46, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x07, 0x4a, -0x0f, 0x88, 0x43, 0x00, 0xd7, 0x52, 0x02, 0x31, 0x01, 0x30, 0x00, 0x04, -0x00, 0x0c, 0x25, 0x28, 0xf6, 0xdb, 0x42, 0xb0, 0x80, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x70, 0x67, 0x21, 0x40, 0xfc, 0x46, 0x60, 0x47, -0x00, 0x00, 0xa0, 0xe3, 0xb4, 0x22, 0x9f, 0xe5, +0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88, +0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04, +0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07, +0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3, +0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0, +0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3, +0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a, +0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c, +0xff, 0xf7, 0x0e, 0xfe, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23, +0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, +0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, +0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40, +0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d, +0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c, +0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69, +0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59, +0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b, +0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc, +0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78, +0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43, +0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c, +0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x8c, 0xf8, +0x00, 0xf0, 0x9e, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xad, 0xfa, 0x3d, 0x70, +0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x85, 0xf8, 0x00, 0xf0, +0x8d, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0x9c, 0xfa, 0x38, 0x0a, 0xf6, 0xd3, +0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, 0x41, 0x02, +0x53, 0x20, 0x00, 0xf0, 0x57, 0xf8, 0x00, 0xf0, 0x8f, 0xfa, 0xff, 0xf7, +0xe9, 0xff, 0x00, 0x24, 0x00, 0x26, 0x00, 0x25, 0x00, 0x27, 0x30, 0x1c, +0x01, 0x36, 0x00, 0xf0, 0x5f, 0xf8, 0x00, 0xf0, 0x71, 0xf9, 0x00, 0x90, +0x00, 0xf0, 0x80, 0xfa, 0xf8, 0x00, 0x00, 0x99, 0x81, 0x40, 0x0d, 0x43, +0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xee, 0xd3, 0x02, 0x99, 0x20, 0xc1, +0x02, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42, 0xe5, 0xd3, 0x03, 0xb0, +0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, +0x16, 0x48, 0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, +0x00, 0x26, 0x20, 0xcf, 0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, +0x28, 0x1c, 0x00, 0xf0, 0xd3, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xd0, 0xf9, +0x28, 0x0c, 0x00, 0xf0, 0xcd, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xca, 0xf9, +0x00, 0xf0, 0x50, 0xfa, 0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, +0x83, 0x20, 0x00, 0xf0, 0x0f, 0xf8, 0x00, 0xf0, +0x47, 0xfa, 0xff, 0xf7, 0xa1, 0xff, 0x04, 0x48, 0xc0, 0x6f, 0x40, 0x23, +0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x00, 0xf0, +0x4d, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xaa, 0xf9, 0x38, 0x0c, 0x00, 0xf0, +0xa7, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xa4, 0xf9, 0x38, 0x1c, 0x00, 0xf0, +0xa1, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, +0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x96, 0xf9, +0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 0x31, 0xfa, 0x57, 0x20, +0x00, 0xf0, 0x8e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x08, 0x4f, +0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, +0xff, 0xf7, 0x73, 0xff, 0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, +0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, +0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43, +0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x89, 0xff, 0xf8, 0x6f, 0x20, 0x23, +0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x6f, +0x20, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0x41, 0x02, 0x53, 0x20, +0xff, 0xf7, 0xa6, 0xff, 0x00, 0xf0, 0xde, 0xf9, 0xff, 0xf7, 0x38, 0xff, +0xf8, 0x1d, 0x05, 0x30, 0x44, 0x1c, 0xff, 0xf7, 0xb1, 0xff, 0x00, 0xf0, +0xc3, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0xd2, 0xf9, 0x20, 0x1c, 0xff, 0xf7, +0xa9, 0xff, 0x00, 0xf0, 0xbb, 0xf8, 0x04, 0x1c, 0x00, 0xf0, 0xca, 0xf9, +0xe8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x21, 0x02, +0x39, 0x43, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, +0x17, 0x1c, 0x61, 0x02, 0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, +0x9a, 0x43, 0x02, 0x60, 0x53, 0x20, 0xff, 0xf7, 0x73, 0xff, 0x00, 0xf0, +0xab, 0xf9, 0xff, 0xf7, 0x05, 0xff, 0x68, 0x46, 0xff, 0xf7, 0xec, 0xfe, +0x6a, 0x46, 0xe8, 0x1d, 0x05, 0x30, 0x17, 0x54, 0x39, 0x0a, 0x68, 0x44, +0x41, 0x70, 0x68, 0x46, 0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xd0, 0xfe, +0x02, 0xab, 0x18, 0x70, 0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21, +0xff, 0xf7, 0xc8, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x20, 0x1c, +0xff, 0xf7, 0x1f, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, +0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x6b, 0x46, +0x00, 0x20, 0xc4, 0x43, 0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, +0x68, 0x46, 0x0c, 0x30, 0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, +0x0e, 0x88, 0xc0, 0x46, 0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, +0x02, 0x30, 0x02, 0x31, 0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, +0x18, 0x1c, 0x11, 0x1c, 0xff, 0xf7, 0x96, 0xfe, 0x04, 0x1c, 0x00, 0x20, +0x01, 0x90, 0x02, 0xab, 0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, +0x0c, 0x21, 0xff, 0xf7, 0x8b, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, +0x1d, 0x06, 0x2d, 0x0e, 0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, +0xff, 0xf7, 0x4a, 0xff, 0x01, 0x20, 0xac, 0x42, +0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02, 0x14, 0x4c, 0xe0, 0x6f, +0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0x53, 0x20, 0xff, 0xf7, +0xfb, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7, 0x8d, 0xfe, 0x68, 0x46, +0xff, 0xf7, 0x74, 0xfe, 0xe0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, +0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24, 0x02, 0xab, 0x5c, 0x70, +0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x56, 0xfe, 0xa8, 0x42, 0x02, 0xd1, +0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c, 0x00, 0xe0, 0x01, 0x20, +0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, +0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3, 0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x03, 0x80, 0xe1, @@ -3675,17 +3858,17 @@ 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, +0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, +0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, +0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, -0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, +0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, -0x00, 0x10, 0x82, 0xe5, 0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, +0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, -0xa0, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, -0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, -0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, -0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, +0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, @@ -3714,82 +3897,82 @@ 0x0a, 0x60, 0x70, 0x47, 0xb0, 0x6e, 0x21, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0x00, 0x24, 0x00, 0x2f, 0x21, 0xd0, 0x00, 0x26, 0xf8, 0x79, 0x00, 0x28, 0x1b, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, 0x05, 0x35, 0x00, 0x7b, -0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x92, 0xfb, 0x01, 0x1c, 0x8b, 0x68, +0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x9e, 0xfb, 0x01, 0x1c, 0x8b, 0x68, 0x00, 0x2b, 0x08, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xca, 0x68, -0xa9, 0x68, 0xfb, 0xf7, 0x4a, 0xfb, 0x00, 0x20, 0x68, 0x60, 0x70, 0x1c, +0xa9, 0x68, 0xfa, 0xf7, 0x4e, 0xff, 0x00, 0x20, 0x68, 0x60, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0xf8, 0x79, 0xb0, 0x42, 0xe3, 0xdc, 0xff, 0x20, -0x38, 0x72, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, -0x81, 0xb0, 0x0f, 0x1c, 0x68, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x00, 0x28, -0x01, 0xd1, 0x0d, 0x20, 0x37, 0xe0, 0xb9, 0x88, 0xc0, 0x46, 0x01, 0x80, -0xf9, 0x88, 0xc0, 0x46, 0x41, 0x80, 0xb9, 0x7a, 0xc0, 0x46, 0x41, 0x71, -0xf9, 0x7a, 0xc0, 0x46, 0x81, 0x71, 0x8c, 0x21, 0x01, 0x71, 0x3d, 0x7e, -0x00, 0x21, 0x00, 0x23, 0x00, 0x2d, 0x1f, 0xdd, 0x1a, 0x01, 0xd2, 0x19, -0x1c, 0x32, 0x16, 0x78, 0x05, 0x2e, 0x0d, 0xdc, 0x0c, 0x01, 0x24, 0x18, -0x26, 0x73, 0x96, 0x68, 0xc0, 0x46, 0x66, 0x61, 0xd6, 0x68, 0xc0, 0x46, -0x26, 0x61, 0x00, 0x24, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e, 0xd4, 0x60, -0x5a, 0x1c, 0x13, 0x06, 0x1b, 0x0e, 0xab, 0x42, 0xe6, 0xdb, 0x00, 0x29, -0x04, 0xd0, 0xc1, 0x71, 0x00, 0x99, 0xc0, 0x46, +0x38, 0x72, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, 0x0f, 0x1c, 0x68, 0x46, 0xff, 0xf7, +0xbd, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, 0x37, 0xe0, 0xb9, 0x88, +0xc0, 0x46, 0x01, 0x80, 0xf9, 0x88, 0xc0, 0x46, 0x41, 0x80, 0xb9, 0x7a, +0xc0, 0x46, 0x41, 0x71, 0xf9, 0x7a, 0xc0, 0x46, 0x81, 0x71, 0x8c, 0x21, +0x01, 0x71, 0x3d, 0x7e, 0x00, 0x21, 0x00, 0x23, 0x00, 0x2d, 0x1f, 0xdd, +0x1a, 0x01, 0xd2, 0x19, 0x1c, 0x32, 0x16, 0x78, 0x05, 0x2e, 0x0d, 0xdc, +0x0c, 0x01, 0x24, 0x18, 0x26, 0x73, 0x96, 0x68, 0xc0, 0x46, 0x66, 0x61, +0xd6, 0x68, 0xc0, 0x46, 0x26, 0x61, 0x00, 0x24, 0x01, 0x31, 0x09, 0x06, +0x09, 0x0e, 0xd4, 0x60, 0x5a, 0x1c, 0x13, 0x06, 0x1b, 0x0e, 0xab, 0x42, +0xe6, 0xdb, 0x00, 0x29, 0x04, 0xd0, 0xc1, 0x71, 0x00, 0x99, 0xc0, 0x46, 0x01, 0x72, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x99, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x20, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x07, 0x1c, 0x38, 0x7e, 0x00, 0x28, 0x28, 0xd0, 0x01, 0x38, 0x05, 0x06, 0x2d, 0x0e, 0x00, 0x26, 0xff, 0x2d, 0x21, 0xd0, 0x28, 0x01, 0xc0, 0x19, 0xc4, 0x1d, 0x15, 0x34, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, -0x1f, 0xfb, 0x01, 0x1c, 0x11, 0xd0, 0x8a, 0x68, 0x00, 0x2a, 0x0c, 0xd0, +0x2b, 0xfb, 0x01, 0x1c, 0x11, 0xd0, 0x8a, 0x68, 0x00, 0x2a, 0x0c, 0xd0, 0xe0, 0x68, 0x00, 0x28, 0x09, 0xd0, 0x00, 0x23, 0xcb, 0x56, 0x05, 0x2b, -0x05, 0xdc, 0x13, 0x1c, 0xca, 0x68, 0xa1, 0x68, 0xfb, 0xf7, 0xd1, 0xfa, +0x05, 0xdc, 0x13, 0x1c, 0xca, 0x68, 0xa1, 0x68, 0xfa, 0xf7, 0xd5, 0xfe, 0xe6, 0x60, 0xff, 0x20, 0x20, 0x70, 0x68, 0x1e, 0x05, 0x06, 0x2d, 0x0e, 0xff, 0x2d, 0xdd, 0xd1, 0x3e, 0x76, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x13, 0x20, 0x70, 0x47, 0xf0, 0xb5, 0x82, 0xb0, 0x07, 0x1c, 0xf8, 0x1d, 0xd5, 0x30, 0x39, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x00, 0x90, 0x00, 0x98, 0x00, 0x28, 0x3b, 0xd1, 0x38, 0x7e, 0xc0, 0x46, 0x01, 0x90, 0x00, 0x26, 0x01, 0x98, 0x00, 0x28, 0x2d, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, -0x15, 0x35, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0xe4, 0xfa, +0x15, 0x35, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x1c, 0x20, 0x69, 0x00, 0x28, 0x17, 0xd0, 0x28, 0x78, 0x05, 0x28, 0x0d, 0xdd, 0xe9, 0x68, 0xaa, 0x68, 0x60, 0x68, 0x40, 0x08, 0x40, 0x00, -0x01, 0xf0, 0x0e, 0xf8, 0x09, 0x22, 0xe8, 0x68, 0xa9, 0x68, 0xfb, 0xf7, -0x87, 0xf9, 0x00, 0x20, 0xe8, 0x60, 0x21, 0x69, 0x28, 0x1c, 0xfb, 0xf7, -0x8c, 0xfa, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x90, 0x00, 0x98, 0x00, 0x28, +0x01, 0xf0, 0x2c, 0xf8, 0x09, 0x22, 0xe8, 0x68, 0xa9, 0x68, 0xfa, 0xf7, +0x8b, 0xfd, 0x00, 0x20, 0xe8, 0x60, 0x21, 0x69, 0x28, 0x1c, 0xfa, 0xf7, +0x90, 0xfe, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x90, 0x00, 0x98, 0x00, 0x28, 0x0c, 0xd1, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0x01, 0x98, 0x86, 0x42, 0xd1, 0xdb, 0x00, 0x20, 0x38, 0x76, 0x00, 0x98, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x82, 0xff, 0xf6, 0xe7, 0xc1, 0x1d, 0x79, 0x31, 0x4a, 0x6b, 0xc0, 0x46, 0xca, 0x63, 0xc1, 0x1d, 0xb9, 0x31, 0x0a, 0x60, 0x00, 0x22, 0x8a, 0x60, 0x04, 0x4a, 0xc0, 0x46, 0x4a, 0x61, 0x8a, 0x61, 0x01, 0x21, 0xd0, 0x30, 0x41, 0x70, 0x08, 0x1c, -0x70, 0x47, 0x00, 0x00, 0xb9, 0xbd, 0x21, 0x40, 0xf8, 0xb5, 0x07, 0x1c, +0x70, 0x47, 0x00, 0x00, 0xb1, 0xc5, 0x21, 0x40, 0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x20, 0x00, 0x90, 0xfe, 0x1d, 0xc9, 0x36, 0x30, 0x78, 0x00, 0x01, 0xc0, 0x19, 0xc4, 0x1d, 0x15, 0x34, 0x80, 0x6a, 0x45, 0x08, 0x6d, 0x00, 0x04, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xb2, 0xfe, 0x31, 0x78, 0x40, 0x18, 0x01, 0x06, 0x09, 0x0e, 0x00, 0x20, 0xa2, 0x68, 0x00, 0x2a, 0x0a, 0xd9, 0x2a, 0x78, 0x4a, 0x40, 0x2a, 0x70, 0x01, 0x30, 0x09, 0x18, 0x09, 0x06, -0x09, 0x0e, 0xa2, 0x68, 0x01, 0x35, 0x82, 0x42, 0xf4, 0xd8, 0xe0, 0x68, -0xa1, 0x68, 0x40, 0x08, 0x40, 0x00, 0xff, 0xf7, 0x99, 0xfe, 0x61, 0x78, -0x81, 0x42, 0x0a, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xf8, 0xf8, 0x1d, -0x79, 0x30, 0x80, 0x6b, 0xf9, 0x1d, 0xb9, 0x31, 0xc8, 0x60, 0x0c, 0x20, -0x00, 0x90, 0x30, 0x78, 0x01, 0x30, 0x30, 0x70, 0x00, 0x98, 0xf8, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 0xc9, 0x32, 0x11, 0x78, 0x09, 0x01, -0x09, 0x18, 0x09, 0x6a, 0xc3, 0x1d, 0x79, 0x33, 0xd9, 0x63, 0x13, 0x78, -0x1b, 0x01, 0x1b, 0x18, 0x5b, 0x6a, 0xcb, 0x18, 0xc1, 0x1d, 0xb9, 0x31, -0x0b, 0x60, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, 0x9b, 0x6a, 0xc0, 0x46, -0x8b, 0x60, 0x07, 0x4b, 0xc0, 0x46, 0x4b, 0x61, 0x12, 0x78, 0x00, 0x7e, -0x01, 0x32, 0x82, 0x42, 0x01, 0xdb, 0x04, 0x48, +0x09, 0x0e, 0xa2, 0x68, 0x01, 0x35, 0x82, 0x42, +0xf4, 0xd8, 0xe0, 0x68, 0xa1, 0x68, 0x40, 0x08, 0x40, 0x00, 0xff, 0xf7, +0x99, 0xfe, 0x61, 0x78, 0x81, 0x42, 0x0a, 0xd0, 0x38, 0x1c, 0x00, 0xf0, +0x0f, 0xf8, 0xf8, 0x1d, 0x79, 0x30, 0x80, 0x6b, 0xf9, 0x1d, 0xb9, 0x31, +0xc8, 0x60, 0x0c, 0x20, 0x00, 0x90, 0x30, 0x78, 0x01, 0x30, 0x30, 0x70, +0x00, 0x98, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 0xc9, 0x32, +0x11, 0x78, 0x09, 0x01, 0x09, 0x18, 0x09, 0x6a, 0xc3, 0x1d, 0x79, 0x33, +0xd9, 0x63, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, 0x5b, 0x6a, 0xcb, 0x18, +0xc1, 0x1d, 0xb9, 0x31, 0x0b, 0x60, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, +0x9b, 0x6a, 0xc0, 0x46, 0x8b, 0x60, 0x07, 0x4b, 0xc0, 0x46, 0x4b, 0x61, +0x12, 0x78, 0x00, 0x7e, 0x01, 0x32, 0x82, 0x42, 0x01, 0xdb, 0x04, 0x48, 0x00, 0xe0, 0x04, 0x48, 0xc0, 0x46, 0x88, 0x61, 0x00, 0x20, 0x70, 0x47, -0x81, 0xbe, 0x21, 0x40, 0x55, 0xbe, 0x21, 0x40, 0x01, 0xbf, 0x21, 0x40, +0x79, 0xc6, 0x21, 0x40, 0x4d, 0xc6, 0x21, 0x40, 0xf9, 0xc6, 0x21, 0x40, 0xf8, 0xb5, 0x04, 0x1c, 0x00, 0x20, 0x00, 0x90, 0x25, 0x7e, 0x29, 0x01, 0xe0, 0x1d, 0x15, 0x30, 0xff, 0xf7, 0x4e, 0xfe, 0xa1, 0x7e, 0x81, 0x42, 0x0a, 0xd0, 0x20, 0x1c, 0x00, 0xf0, 0x61, 0xf8, 0xe0, 0x1d, 0x79, 0x30, 0x80, 0x6b, 0xe1, 0x1d, 0xb9, 0x31, 0xc8, 0x60, 0x0b, 0x20, 0x55, 0xe0, 0x00, 0x27, 0x00, 0x2d, 0x0f, 0xdd, 0x38, 0x01, 0x00, 0x19, 0x00, 0x7f, -0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x10, 0xfa, 0x00, 0x28, 0x01, 0xd1, +0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x1c, 0xfa, 0x00, 0x28, 0x01, 0xd1, 0x09, 0x20, 0x47, 0xe0, 0x78, 0x1c, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xef, 0xdb, 0x00, 0x26, 0x00, 0x2d, 0x38, 0xdd, 0x30, 0x01, 0x00, 0x19, 0xc7, 0x1d, 0x15, 0x37, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, -0xfb, 0xf9, 0x00, 0x23, 0xc1, 0x56, 0x05, 0x29, 0x0c, 0xdc, 0x42, 0x68, -0x00, 0x2a, 0x04, 0xd0, 0xc1, 0x68, 0xb8, 0x68, 0xfb, 0xf7, 0xb2, 0xf9, +0x07, 0xfa, 0x00, 0x23, 0xc1, 0x56, 0x05, 0x29, 0x0c, 0xdc, 0x42, 0x68, +0x00, 0x2a, 0x04, 0xd0, 0xc1, 0x68, 0xb8, 0x68, 0xfa, 0xf7, 0xb6, 0xfd, 0xf8, 0x60, 0xf8, 0x68, 0x00, 0x28, 0x1b, 0xd1, 0x0e, 0x20, 0x17, 0xe0, -0xc0, 0x68, 0x00, 0x28, 0x07, 0xd0, 0xfb, 0xf7, 0xa5, 0xf9, 0x00, 0x28, +0xc0, 0x68, 0x00, 0x28, 0x07, 0xd0, 0xfa, 0xf7, 0xa9, 0xfd, 0x00, 0x28, 0x05, 0xda, 0x40, 0x42, 0xb9, 0x68, 0x81, 0x42, 0x04, 0xd0, 0x05, 0x20, 0x0a, 0xe0, 0xb9, 0x68, 0x81, 0x42, 0xfa, 0xd8, 0x09, 0x21, 0xb8, 0x68, -0xfb, 0xf7, 0x7a, 0xf8, 0xf8, 0x60, 0x00, 0x28, 0x02, 0xd1, 0x06, 0x20, +0xfa, 0xf7, 0x7e, 0xfc, 0xf8, 0x60, 0x00, 0x28, 0x02, 0xd1, 0x06, 0x20, 0x00, 0x90, 0x07, 0xe0, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0xae, 0x42, 0xc6, 0xdb, 0x00, 0x98, 0x00, 0x28, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0x92, 0xfe, 0x00, 0x98, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, @@ -3797,25 +3980,25 @@ 0x8a, 0x18, 0xc1, 0x1d, 0xb9, 0x31, 0x0a, 0x60, 0xc2, 0x1d, 0x15, 0x32, 0x8a, 0x60, 0x05, 0x4a, 0xc0, 0x46, 0x4a, 0x61, 0x04, 0x4a, 0xc0, 0x46, 0x8a, 0x61, 0x00, 0x21, 0xd0, 0x30, 0x01, 0x70, 0x08, 0x1c, 0x70, 0x47, -0x59, 0xbf, 0x21, 0x40, 0x01, 0xbf, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, +0x51, 0xc7, 0x21, 0x40, 0xf9, 0xc6, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0x1d, 0x4b, 0x98, 0x42, 0x03, 0xd0, 0x03, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1c, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xbc, 0xfd, 0xfc, 0x1d, 0x79, 0x34, 0x00, 0x28, 0x09, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x2d, 0xf8, 0xf9, 0x1d, 0xb9, 0x31, 0xa0, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x0a, 0x20, 0xea, 0xe7, 0x38, 0x7a, 0x1c, 0x28, 0x04, 0xd0, 0x78, 0x7a, 0x10, 0x28, 0x01, 0xd0, 0x04, 0x20, 0xe2, 0xe7, 0xb8, 0x7a, 0x01, 0x28, -0x01, 0xd0, 0x07, 0x20, 0xdd, 0xe7, 0x60, 0x6b, 0xf9, 0x68, 0x88, 0x42, -0x01, 0xd0, 0x05, 0x20, 0xd7, 0xe7, 0x38, 0x69, 0x00, 0x28, 0x04, 0xd0, -0x06, 0x4b, 0x98, 0x42, 0x01, 0xd0, 0x08, 0x20, 0xcf, 0xe7, 0x38, 0x7e, -0x08, 0x28, 0x01, 0xdd, 0x12, 0x20, 0xca, 0xe7, 0x00, 0x20, 0xc8, 0xe7, -0x73, 0x6e, 0x69, 0x70, 0x17, 0x40, 0x00, 0x02, 0xb8, 0xb5, 0x07, 0x1c, -0x38, 0x1c, 0xff, 0xf7, 0x2a, 0xfe, 0x00, 0x25, 0xf8, 0x1d, 0xc9, 0x30, -0x45, 0x70, 0xfc, 0x1d, 0xb9, 0x34, 0xe5, 0x61, 0x68, 0x46, 0xff, 0xf7, -0x9d, 0xfd, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, 0x0d, 0xe0, 0xf8, 0x1d, -0x79, 0x30, 0x85, 0x63, 0xc5, 0x63, 0x1b, 0x20, 0x20, 0x60, 0xa7, 0x60, -0x04, 0x48, 0xc0, 0x46, 0x60, 0x61, 0x04, 0x48, 0xc0, 0x46, 0xa0, 0x61, -0x28, 0x1c, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0x75, 0xc0, 0x21, 0x40, 0x3b, 0xc0, 0x21, 0x40, 0xf0, 0xb5, 0x82, 0xb0, +0x01, 0xd0, 0x07, 0x20, 0xdd, 0xe7, 0x60, 0x6b, +0xf9, 0x68, 0x88, 0x42, 0x01, 0xd0, 0x05, 0x20, 0xd7, 0xe7, 0x38, 0x69, +0x00, 0x28, 0x04, 0xd0, 0x06, 0x4b, 0x98, 0x42, 0x01, 0xd0, 0x08, 0x20, +0xcf, 0xe7, 0x38, 0x7e, 0x08, 0x28, 0x01, 0xdd, 0x12, 0x20, 0xca, 0xe7, +0x00, 0x20, 0xc8, 0xe7, 0x73, 0x6e, 0x69, 0x70, 0x02, 0x10, 0x00, 0x03, +0xb8, 0xb5, 0x07, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x2a, 0xfe, 0x00, 0x25, +0xf8, 0x1d, 0xc9, 0x30, 0x45, 0x70, 0xfc, 0x1d, 0xb9, 0x34, 0xe5, 0x61, +0x68, 0x46, 0xff, 0xf7, 0x9d, 0xfd, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, +0x0d, 0xe0, 0xf8, 0x1d, 0x79, 0x30, 0x85, 0x63, 0xc5, 0x63, 0x1b, 0x20, +0x20, 0x60, 0xa7, 0x60, 0x04, 0x48, 0xc0, 0x46, 0x60, 0x61, 0x04, 0x48, +0xc0, 0x46, 0xa0, 0x61, 0x28, 0x1c, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x6d, 0xc8, 0x21, 0x40, 0x33, 0xc8, 0x21, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 0x07, 0x1c, 0x00, 0x20, 0xfd, 0x1d, 0x79, 0x35, 0xfc, 0x1d, 0xb9, 0x34, 0xe9, 0x6a, 0xc0, 0x46, 0x61, 0x60, 0x62, 0x68, 0xe9, 0x6b, 0x8a, 0x42, 0x03, 0xd2, 0x61, 0x60, 0x2a, 0x6b, 0x91, 0x42, 0x34, 0xd2, 0x66, 0x68, @@ -3823,52 +4006,54 @@ 0x26, 0x68, 0x2a, 0x6b, 0x96, 0x42, 0x00, 0xd2, 0x32, 0x1c, 0x01, 0x9e, 0x96, 0x1b, 0xa2, 0x68, 0xc0, 0x46, 0x00, 0x92, 0x00, 0x2a, 0x09, 0xd0, 0x28, 0x6a, 0x6a, 0x6a, 0x41, 0x18, 0x00, 0x98, 0xc0, 0x18, 0x33, 0x1c, -0xfc, 0xf7, 0xc4, 0xff, 0x00, 0x28, 0x1b, 0xd1, 0x61, 0x68, 0x89, 0x19, +0xfc, 0xf7, 0x68, 0xff, 0x00, 0x28, 0x1b, 0xd1, 0x61, 0x68, 0x89, 0x19, 0x61, 0x60, 0x22, 0x68, 0x91, 0x42, 0x0d, 0xd1, 0x61, 0x69, 0x38, 0x1c, -0xfb, 0xf7, 0xc1, 0xf8, 0x00, 0x06, 0x00, 0x0e, 0x0e, 0xd1, 0xa1, 0x69, -0x38, 0x1c, 0xfb, 0xf7, 0xba, 0xf8, 0x00, 0x06, 0x00, 0x0e, 0x07, 0xd1, +0xfa, 0xf7, 0xc5, 0xfc, 0x00, 0x06, 0x00, 0x0e, 0x0e, 0xd1, 0xa1, 0x69, +0x38, 0x1c, 0xfa, 0xf7, 0xbe, 0xfc, 0x00, 0x06, 0x00, 0x0e, 0x07, 0xd1, 0x61, 0x68, 0x2a, 0x6b, 0x91, 0x42, 0xc2, 0xd3, 0xa9, 0x6b, 0xaa, 0x6a, 0x89, 0x18, 0xa9, 0x63, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xb0, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfb, 0xf7, -0xbf, 0xfa, 0xfa, 0x1d, 0x09, 0x32, 0x32, 0x48, 0x00, 0x21, 0xc9, 0x43, -0xc4, 0x1d, 0xb9, 0x34, 0xe1, 0x60, 0xf9, 0x88, 0xc3, 0x1d, 0x89, 0x33, -0x19, 0x73, 0xc1, 0x1d, 0x79, 0x31, 0xbd, 0x68, 0xc0, 0x46, 0x0d, 0x62, -0xff, 0x68, 0xc0, 0x46, 0x4f, 0x62, 0x17, 0x68, 0xc0, 0x46, 0x8f, 0x62, -0x57, 0x68, 0xc0, 0x46, 0xcf, 0x62, 0x92, 0x68, 0xc0, 0x46, 0x4a, 0x63, -0xca, 0x6a, 0x8f, 0x6a, 0xd2, 0x19, 0x0a, 0x63, 0x1a, 0x7b, 0x01, 0x2a, -0x0d, 0xd0, 0x02, 0x2a, 0x1a, 0xd0, 0x03, 0x2a, 0x2e, 0xd1, 0xc2, 0x1d, -0xc9, 0x32, 0x52, 0x78, 0x00, 0x2a, 0x07, 0xd1, 0x10, 0x20, 0x89, 0x6b, -0xc0, 0x46, 0xe1, 0x60, 0x25, 0xe0, 0xff, 0xf7, 0x4d, 0xff, 0x22, 0xe0, -0xff, 0xf7, 0xac, 0xfd, 0x00, 0x28, 0x1e, 0xd1, 0xe1, 0x69, 0x00, 0x29, -0x1b, 0xd0, 0x09, 0x7a, 0x15, 0x4b, 0xc9, 0x18, 0x02, 0x91, 0x16, 0xe0, -0x8a, 0x6a, 0xcb, 0x6a, 0x9f, 0x18, 0x4d, 0x6b, 0xaf, 0x42, 0x05, 0xd8, -0x00, 0x2a, 0x03, 0xd0, 0x9f, 0x07, 0x01, 0xd1, 0x92, 0x07, 0x01, 0xd0, -0x0f, 0x20, 0x08, 0xe0, 0x89, 0x6b, 0x99, 0x42, 0x01, 0xd0, 0xe1, 0x60, -0xf8, 0xe7, 0xff, 0xf7, 0x53, 0xff, 0x00, 0xe0, 0x10, 0x20, 0x01, 0xab, -0x58, 0x80, 0xe0, 0x68, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, -0xfb, 0xf7, 0x9e, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x3c, 0xac, 0x20, 0x40, 0x0d, 0xf0, 0xfe, 0xca, -0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, -0x4d, 0xfa, 0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, -0x02, 0xd1, 0x00, 0x98, 0xff, 0xf7, 0xc4, 0xfc, 0x02, 0xab, 0x58, 0x80, -0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x7e, 0xf9, 0x01, 0x20, 0x05, 0xb0, -0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, -0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 0x32, 0xfa, 0x68, 0x46, 0xb9, 0x68, -0xff, 0xf7, 0x85, 0xfc, 0x00, 0x28, 0x00, 0xd1, 0x02, 0x20, 0x02, 0xab, -0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x65, 0xf9, 0x01, 0x20, -0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x85, 0xb0, -0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, -0x19, 0xfa, 0x3c, 0x69, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 0x14, 0xfa, -0x68, 0x46, 0x21, 0x1c, 0xff, 0xf7, 0x67, 0xfc, 0x8c, 0x24, 0x00, 0x28, +0xf0, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfa, 0xf7, +0xc3, 0xfe, 0xfa, 0x1d, 0x09, 0x32, 0x37, 0x49, 0x00, 0x20, 0xc0, 0x43, +0xcc, 0x1d, 0xb9, 0x34, 0xe0, 0x60, 0xf8, 0x88, 0xcb, 0x1d, 0x89, 0x33, +0x18, 0x73, 0xc8, 0x1d, 0x79, 0x30, 0xbd, 0x68, 0xc0, 0x46, 0x05, 0x62, +0xff, 0x68, 0xc0, 0x46, 0x47, 0x62, 0x17, 0x68, 0xc0, 0x46, 0x87, 0x62, +0x57, 0x68, 0xc0, 0x46, 0xc7, 0x62, 0x92, 0x68, 0xc0, 0x46, 0x42, 0x63, +0xc2, 0x6a, 0x87, 0x6a, 0xd2, 0x19, 0x02, 0x63, 0x1a, 0x7b, 0x28, 0x4d, +0x01, 0x2a, 0x0d, 0xd0, 0x02, 0x2a, 0x1c, 0xd0, 0x03, 0x2a, 0x35, 0xd1, +0xca, 0x1d, 0xc9, 0x32, 0x52, 0x78, 0x00, 0x2a, 0x08, 0xd1, 0x10, 0x27, +0x80, 0x6b, 0xc0, 0x46, 0xe0, 0x60, 0x2c, 0xe0, 0x08, 0x1c, 0xff, 0xf7, +0x4b, 0xff, 0x22, 0xe0, 0x08, 0x1c, 0xff, 0xf7, 0xa9, 0xfd, 0x07, 0x1c, +0x23, 0xd1, 0xe0, 0x69, 0x00, 0x28, 0x1c, 0xd0, 0x00, 0x7a, 0x1a, 0x4b, +0xc0, 0x18, 0x02, 0x90, 0x17, 0xe0, 0x82, 0x6a, 0xc3, 0x6a, 0x9f, 0x18, +0x46, 0x6b, 0xb7, 0x42, 0x05, 0xd8, 0x00, 0x2a, 0x03, 0xd0, 0x9f, 0x07, +0x01, 0xd1, 0x92, 0x07, 0x01, 0xd0, 0x0f, 0x27, 0x0d, 0xe0, 0x80, 0x6b, +0x98, 0x42, 0x01, 0xd0, 0xe0, 0x60, 0xf8, 0xe7, 0x08, 0x1c, 0xff, 0xf7, +0x4f, 0xff, 0x07, 0x1c, 0x03, 0xd1, 0x00, 0xf0, 0x1f, 0xfe, 0x01, 0xe0, +0x10, 0x27, 0x00, 0x20, 0x28, 0x65, 0x01, 0xab, 0x5f, 0x80, 0xe0, 0x68, +0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, +0xfa, 0xf7, 0x98, 0xfd, 0x01, 0x20, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x3c, 0xac, 0x20, 0x40, 0x00, 0x00, 0x00, 0x80, +0x0d, 0xf0, 0xfe, 0xca, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, +0x01, 0xa9, 0xfa, 0xf7, 0x45, 0xfe, 0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, +0x94, 0xfc, 0x00, 0x28, 0x02, 0xd1, 0x00, 0x98, 0xff, 0xf7, 0xb8, 0xfc, +0x02, 0xab, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, 0x76, 0xfd, +0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, +0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, 0x2a, 0xfe, +0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, 0x79, 0xfc, 0x00, 0x28, 0x00, 0xd1, +0x02, 0x20, 0x02, 0xab, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, +0x5d, 0xfd, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x90, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, +0x11, 0xfe, 0x3c, 0x69, 0x38, 0x1c, 0x01, 0xa9, 0xfa, 0xf7, 0x0c, 0xfe, +0x68, 0x46, 0x21, 0x1c, 0xff, 0xf7, 0x5b, 0xfc, 0x8c, 0x24, 0x00, 0x28, 0x0e, 0xd1, 0xb9, 0x68, 0x00, 0x29, 0x02, 0xd1, 0xfa, 0x68, 0x00, 0x2a, 0x08, 0xd0, 0xf8, 0x88, 0x23, 0x1c, 0x8c, 0x28, 0x00, 0xd8, 0x03, 0x1c, -0xf8, 0x68, 0x00, 0x9a, 0xfc, 0xf7, 0x38, 0xfe, 0x02, 0xab, 0x58, 0x80, -0x03, 0x94, 0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x37, 0xf9, 0x01, 0x20, +0xf8, 0x68, 0x00, 0x9a, 0xfc, 0xf7, 0xd0, 0xfd, 0x02, 0xab, 0x58, 0x80, +0x03, 0x94, 0x00, 0x21, 0x01, 0xa8, 0xfa, 0xf7, 0x2f, 0xfd, 0x01, 0x20, 0x05, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0x04, 0x48, 0xff, 0x22, 0x02, 0x72, 0x8c, 0x30, 0x01, 0x31, 0x04, 0x29, 0xfa, 0xd3, 0x70, 0x47, 0x00, 0x00, 0xb0, 0x6e, 0x21, 0x40, 0x02, 0x48, 0x03, 0x49, -0x40, 0x1a, 0x40, 0x42, 0x70, 0x47, 0x00, 0x00, 0xb9, 0xce, 0x21, 0x40, -0xb5, 0xce, 0x21, 0x40, 0x00, 0x21, 0x08, 0x4a, 0x8b, 0x00, 0x5b, 0x18, +0x40, 0x1a, 0x40, 0x42, 0x70, 0x47, 0x00, 0x00, 0xed, 0xd6, 0x21, 0x40, +0xe9, 0xd6, 0x21, 0x40, 0x00, 0x21, 0x08, 0x4a, 0x8b, 0x00, 0x5b, 0x18, 0x9b, 0x00, 0xd3, 0x56, 0x83, 0x42, 0x04, 0xd1, 0x88, 0x00, 0x40, 0x18, 0x80, 0x00, 0x80, 0x18, 0x70, 0x47, 0x01, 0x31, 0x01, 0x29, 0xf1, 0xd3, 0x00, 0x20, 0xf9, 0xe7, 0xe0, 0x70, 0x21, 0x40, 0x80, 0xb5, 0x00, 0xf0, @@ -3883,212 +4068,215 @@ 0x02, 0x6b, 0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18, 0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63, 0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, -0xc9, 0x6a, 0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x10, 0x2a, 0x00, 0x80, +0xc9, 0x6a, 0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8, 0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22, 0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42, 0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, -0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22, -0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0, -0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c, -0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60, -0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00, -0x08, 0x83, 0x20, 0x40, 0x10, 0x2a, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, -0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x00, 0x27, 0x68, 0x46, 0xfe, 0xf7, -0xa7, 0xfb, 0x10, 0x4c, 0x00, 0x28, 0x0b, 0xd0, 0x00, 0xf0, 0x3e, 0xf8, -0x00, 0x28, 0x07, 0xd0, 0x01, 0x27, 0x10, 0x23, 0x20, 0x68, 0x18, 0x43, -0x20, 0x60, 0x60, 0x68, 0x18, 0x43, 0x0b, 0xe0, 0x10, 0x23, 0xa0, 0x68, -0x98, 0x43, 0xa0, 0x60, 0x20, 0x69, 0x98, 0x43, 0x20, 0x61, 0x20, 0x68, -0x98, 0x43, 0x20, 0x60, 0x60, 0x68, 0x98, 0x43, 0x60, 0x60, 0x38, 0x1c, -0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, -0xe8, 0x18, 0x00, 0x80, 0x00, 0xb5, 0x00, 0xf0, 0xb5, 0xfc, 0xfe, 0xf7, -0xc5, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x14, 0x24, +0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x22, 0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, +0x02, 0x28, 0x0c, 0xd0, 0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, +0x08, 0x60, 0x10, 0x1c, 0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, +0x50, 0x22, 0x08, 0x60, 0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, +0xf3, 0xe7, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, +0x0c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x00, 0x27, +0x68, 0x46, 0xfe, 0xf7, 0x6f, 0xfb, 0x10, 0x4c, 0x00, 0x28, 0x0b, 0xd0, +0x00, 0xf0, 0x44, 0xf8, 0x00, 0x28, 0x07, 0xd0, 0x01, 0x27, 0x10, 0x23, +0x60, 0x68, 0x18, 0x43, 0x60, 0x60, 0xa0, 0x68, 0x18, 0x43, 0x0b, 0xe0, +0x10, 0x23, 0xe0, 0x68, 0x98, 0x43, 0xe0, 0x60, 0x60, 0x69, 0x98, 0x43, +0x60, 0x61, 0x60, 0x68, 0x98, 0x43, 0x60, 0x60, 0xa0, 0x68, 0x98, 0x43, +0xa0, 0x60, 0x38, 0x1c, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, +0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0x00, 0xf0, 0xc7, 0xfc, 0x04, 0x49, +0x09, 0x6d, 0x08, 0x43, 0xfe, 0xf7, 0x8a, 0xfb, 0x00, 0x20, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x14, 0x24, 0x00, 0x25, 0x00, 0x27, 0x08, 0x4e, 0x02, 0x20, 0x21, 0x1c, 0x32, 0x1c, -0xfa, 0xf7, 0xec, 0xfe, 0x78, 0x40, 0x07, 0x04, 0x3f, 0x0c, 0x02, 0x34, +0xfa, 0xf7, 0xde, 0xfa, 0x78, 0x40, 0x07, 0x04, 0x3f, 0x0c, 0x02, 0x34, 0x01, 0x35, 0x03, 0x2d, 0xf3, 0xd3, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x39, 0xb7, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x24, -0x20, 0x1c, 0x10, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, 0x00, 0x20, -0x00, 0x06, 0x00, 0x0e, 0x16, 0xd0, 0x0d, 0x4a, 0x3a, 0x21, 0x02, 0x20, -0xfa, 0xf7, 0xce, 0xfe, 0x07, 0x04, 0x3f, 0x0c, 0x03, 0xd1, 0x00, 0x20, -0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xf7, 0xcf, 0xff, 0xc0, 0x43, -0x00, 0x04, 0x00, 0x0c, 0xb8, 0x42, 0x00, 0xd0, 0x00, 0x24, 0x20, 0x06, -0x00, 0x0e, 0xf1, 0xe7, 0x20, 0x1c, 0xef, 0xe7, 0xe8, 0x0d, 0x00, 0x80, -0x39, 0xb7, 0x21, 0x40, 0xb0, 0xb5, 0x01, 0x27, 0x3a, 0x1c, 0x18, 0x4b, -0xdb, 0x68, 0x01, 0x2b, 0x00, 0xd0, 0x00, 0x22, 0x12, 0x06, 0x12, 0x0e, -0x00, 0x24, 0x00, 0x2a, 0x23, 0xd0, 0x14, 0x4a, 0x53, 0x68, 0x1b, 0x04, -0x1b, 0x0c, 0x1d, 0x02, 0x1b, 0x12, 0x2b, 0x43, 0x92, 0x68, 0x12, 0x04, -0x12, 0x0c, 0x15, 0x02, 0x12, 0x12, 0x2a, 0x43, 0x12, 0x04, 0x12, 0x0c, -0x1b, 0x04, 0x1a, 0x43, 0x51, 0x40, 0x01, 0x31, 0x0f, 0xd1, 0x00, 0x28, -0x02, 0xd0, 0xff, 0xf7, 0x9b, 0xff, 0xc4, 0x43, 0x22, 0x04, 0x12, 0x0c, -0x07, 0x4b, 0x3a, 0x21, 0x02, 0x20, 0xfa, 0xf7, 0x8a, 0xfe, 0x38, 0x1c, -0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0x00, 0x00, -0xe8, 0x0d, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40, 0x7b, 0xb7, 0x21, 0x40, -0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a, 0xc0, 0x46, 0x82, 0x60, -0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60, 0x00, 0x20, 0x13, 0x4a, -0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, -0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x0e, 0x4b, -0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, -0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x09, 0x4a, 0x13, 0x5c, -0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, -0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47, 0x17, 0x40, 0x00, 0x02, -0xe8, 0x0d, 0x00, 0x80, 0xfc, 0x03, 0x00, 0x80, 0x05, 0x04, 0x00, 0x80, -0x0e, 0x04, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x21, 0x45, 0x4d, 0xe8, 0x1d, -0x79, 0x30, 0x41, 0x73, 0x01, 0x73, 0x64, 0x22, 0x42, 0x82, 0x82, 0x82, -0xc1, 0x82, 0x7d, 0x21, 0xc9, 0x00, 0x01, 0x83, 0x00, 0x21, 0x41, 0x83, -0x3f, 0x48, 0x01, 0x22, 0x00, 0xf0, 0x08, 0xfb, 0x00, 0x26, 0xf6, 0x43, -0x3d, 0x4c, 0xe7, 0x1d, 0x39, 0x37, 0xb0, 0x42, 0x07, 0xd1, 0xf8, 0x88, -0x01, 0x30, 0xf8, 0x80, 0xa0, 0x79, 0x01, 0x30, 0xa0, 0x71, 0xfc, 0xf7, -0xb3, 0xfd, 0x38, 0x48, 0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0xf4, 0xfa, -0xb0, 0x42, 0x07, 0xd1, 0xf8, 0x88, 0x01, 0x30, 0xf8, 0x80, 0xa0, 0x79, -0x01, 0x30, 0xa0, 0x71, 0xfc, 0xf7, 0xa4, 0xfd, 0xe8, 0x68, 0x2f, 0x1c, -0x01, 0x28, 0x05, 0xd1, 0x2f, 0x48, 0x7d, 0x22, 0xd2, 0x00, 0x00, 0x21, -0x00, 0xf0, 0xe0, 0xfa, 0x2d, 0x4d, 0x28, 0x1c, 0xfa, 0xf7, 0x02, 0xfe, -0x2c, 0x48, 0xfa, 0xf7, 0xff, 0xfd, 0x2c, 0x48, -0xfa, 0xf7, 0xfc, 0xfd, 0x2b, 0x4e, 0x71, 0x23, 0x5b, 0x01, 0xfc, 0x18, -0x2a, 0x4f, 0x20, 0x79, 0x00, 0x28, 0x0f, 0xd0, 0x28, 0x1c, 0xfa, 0xf7, -0xf1, 0xfd, 0x38, 0x1c, 0xfa, 0xf7, 0xee, 0xfd, 0x00, 0x28, 0x04, 0xd0, -0x38, 0x1c, 0xfa, 0xf7, 0xe9, 0xfd, 0x00, 0x28, 0xfa, 0xd1, 0x30, 0x1c, -0xfa, 0xf7, 0xe4, 0xfd, 0x60, 0x79, 0x00, 0x28, 0x23, 0xd0, 0x28, 0x1c, -0xfa, 0xf7, 0xde, 0xfd, 0x38, 0x1c, 0xfa, 0xf7, 0xdb, 0xfd, 0x00, 0x28, -0x04, 0xd0, 0x38, 0x1c, 0xfa, 0xf7, 0xd6, 0xfd, 0x00, 0x28, 0xfa, 0xd1, -0x19, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x14, 0x20, -0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, -0x89, 0x0a, 0x03, 0xd3, 0x13, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x03, 0xe0, -0x12, 0x49, 0xc0, 0x46, 0x08, 0x64, 0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, -0x1e, 0xfe, 0x10, 0x48, 0xfa, 0xf7, 0xb8, 0xfd, 0x0f, 0x48, 0xfa, 0xf7, -0xb5, 0xfd, 0xbc, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x5d, 0x22, 0xff, 0xff, -0xa0, 0x82, 0x20, 0x40, 0x21, 0x21, 0xff, 0xff, 0x59, 0x7e, 0x21, 0x40, -0xf4, 0x01, 0xff, 0xff, 0x09, 0x2c, 0xff, 0xff, 0x04, 0x02, 0xff, 0xff, -0x00, 0x00, 0xff, 0xff, 0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, -0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x65, 0xa8, 0x21, 0x40, -0x48, 0x57, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20, 0x0f, 0x49, 0xc0, 0x46, -0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21, 0xfa, 0xf7, 0x8e, 0xfd, -0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x08, 0x21, -0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c, 0x07, 0xd1, 0x00, 0x68, -0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x08, 0xbc, -0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64, 0xf9, 0xe7, 0x00, 0x00, -0x00, 0x00, 0x00, 0xb0, 0x25, 0x55, 0xff, 0xff, 0xf8, 0x28, 0x00, 0x80, +0x18, 0x47, 0x00, 0x00, 0x79, 0xbf, 0x21, 0x40, 0x01, 0x20, 0x70, 0x47, +0xb0, 0xb5, 0x01, 0x27, 0x3a, 0x1c, 0x18, 0x4b, 0xdb, 0x68, 0x01, 0x2b, +0x00, 0xd0, 0x00, 0x22, 0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0x00, 0x2a, +0x23, 0xd0, 0x14, 0x4a, 0x53, 0x68, 0x1b, 0x04, 0x1b, 0x0c, 0x1d, 0x02, +0x1b, 0x12, 0x2b, 0x43, 0x92, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x15, 0x02, +0x12, 0x12, 0x2a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x1b, 0x04, 0x1a, 0x43, +0x51, 0x40, 0x01, 0x31, 0x0f, 0xd1, 0x00, 0x28, 0x02, 0xd0, 0xff, 0xf7, +0xc1, 0xff, 0xc4, 0x43, 0x22, 0x04, 0x12, 0x0c, 0x07, 0x4b, 0x3a, 0x21, +0x02, 0x20, 0xfa, 0xf7, 0xa2, 0xfa, 0x38, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, +0x40, 0x00, 0x14, 0x40, 0xd9, 0xbf, 0x21, 0x40, 0x80, 0xb4, 0x03, 0x22, +0xc2, 0x80, 0x15, 0x4a, 0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, +0x01, 0x32, 0xc2, 0x60, 0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, +0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, +0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, +0x0f, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, +0x01, 0x31, 0x00, 0x20, 0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, +0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, +0x80, 0xbc, 0x70, 0x47, 0x02, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, +0x7c, 0x04, 0x00, 0x80, 0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, +0x00, 0xb5, 0x01, 0x23, 0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, +0x00, 0x22, 0x0a, 0x70, 0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, +0x43, 0x83, 0x7d, 0x21, 0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, +0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x38, 0xfb, 0x08, 0xbc, 0x18, 0x47, +0x68, 0x0e, 0x00, 0x80, 0xa1, 0x22, 0xff, 0xff, +0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48, 0x02, 0x22, 0x00, 0x21, +0x00, 0xf0, 0x2a, 0xfb, 0x01, 0x23, 0xd8, 0x42, 0x0a, 0xd1, 0x10, 0x48, +0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32, 0xca, 0x80, 0x81, 0x79, +0x01, 0x31, 0x81, 0x71, 0xfc, 0xf7, 0x5c, 0xfd, 0x0b, 0x48, 0xc0, 0x68, +0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22, 0xd2, 0x00, 0x00, 0x21, +0x00, 0xf0, 0x12, 0xfb, 0x08, 0x48, 0xfa, 0xf7, 0x1b, 0xfa, 0x08, 0x48, +0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x0a, 0xfb, 0x08, 0xbc, 0x18, 0x47, +0x65, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, +0x95, 0x7e, 0x21, 0x40, 0x81, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, +0x00, 0xb5, 0x10, 0x20, 0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, +0x0f, 0x48, 0x64, 0x21, 0xfa, 0xf7, 0x00, 0xfa, 0x0e, 0x48, 0x01, 0x22, +0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, +0x02, 0x68, 0x12, 0x0c, 0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, +0x08, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, +0xc0, 0x46, 0x01, 0x64, 0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, +0x91, 0x55, 0xff, 0xff, 0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, +0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, +0x01, 0x22, 0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, +0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, +0x03, 0xd3, 0x21, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, +0xc0, 0x46, 0x01, 0x64, 0x1f, 0x48, 0xfa, 0xf7, 0xc1, 0xf9, 0x1f, 0x48, +0xc1, 0x6b, 0xff, 0x29, 0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, +0x0f, 0x1c, 0x1c, 0x4c, 0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, +0xa1, 0x69, 0x99, 0x43, 0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, +0xc0, 0x46, 0x28, 0x61, 0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfa, 0xf7, +0xa9, 0xf9, 0x16, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, +0x39, 0x1c, 0x32, 0x1c, 0xfa, 0xf7, 0xa8, 0xf9, 0x13, 0x48, 0xc1, 0x68, +0x08, 0x29, 0xfc, 0xd1, 0x12, 0x48, 0xfa, 0xf7, 0x97, 0xf9, 0x10, 0x23, +0x60, 0x69, 0x98, 0x43, 0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, +0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, +0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, +0x04, 0x02, 0xff, 0xff, 0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, +0x0c, 0x55, 0xff, 0xff, 0x2d, 0xcf, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, +0x44, 0x80, 0x20, 0x40, 0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, +0x00, 0xb5, 0xfd, 0xf7, 0xeb, 0xfa, 0x06, 0x48, 0xfa, 0xf7, 0x6c, 0xf9, +0xfd, 0xf7, 0xc0, 0xfa, 0xfd, 0xf7, 0xee, 0xfb, 0xfd, 0xf7, 0x00, 0xfc, +0xfd, 0xf7, 0x0e, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, +0x90, 0xb5, 0xfd, 0xf7, 0x55, 0xf8, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, +0xf8, 0x1d, 0x79, 0x30, 0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, +0xf9, 0x67, 0x31, 0x49, 0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, +0x0c, 0x60, 0x4c, 0x60, 0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, +0x8c, 0x61, 0x04, 0xe0, 0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, +0x08, 0x38, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, +0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, +0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, +0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x38, 0xf8, 0x00, 0xf0, 0x08, 0xf9, +0xfc, 0xf7, 0x5f, 0xfc, 0xff, 0xf7, 0x84, 0xfd, 0xfd, 0xf7, 0x18, 0xfa, +0xfd, 0xf7, 0xa0, 0xf9, 0xfd, 0xf7, 0xac, 0xfa, 0xfd, 0xf7, 0x3e, 0xf9, +0xfd, 0xf7, 0xf4, 0xf8, 0xfd, 0xf7, 0x7e, 0xf9, 0x00, 0xf0, 0xc4, 0xf9, +0xfd, 0xf7, 0x86, 0xfb, 0xfd, 0xf7, 0xf4, 0xfa, 0xfd, 0xf7, 0xbc, 0xfa, +0xfd, 0xf7, 0x26, 0xf8, 0xfa, 0xf7, 0x12, 0xf8, 0xff, 0xf7, 0x40, 0xfd, +0x00, 0x20, 0xff, 0xf7, 0x17, 0xfe, 0xff, 0xf7, 0x97, 0xff, 0x71, 0x23, +0x5b, 0x01, 0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, +0xf8, 0x18, 0x04, 0x63, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, +0xc3, 0xf9, 0x08, 0x48, 0xfa, 0xf7, 0xf8, 0xf8, 0x90, 0xbc, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, +0x04, 0x01, 0x11, 0x40, 0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, +0x65, 0x9f, 0x21, 0x40, 0x00, 0xb5, 0x04, 0x48, 0xfa, 0xf7, 0xe4, 0xf8, +0xfd, 0xf7, 0x48, 0xfb, 0xfd, 0xf7, 0x0e, 0xf8, 0x08, 0xbc, 0x18, 0x47, +0x61, 0xa9, 0x21, 0x40, 0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, +0x40, 0x21, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, +0x07, 0x48, 0x41, 0x69, 0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, +0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, +0xc0, 0x46, 0x10, 0x61, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, +0xfe, 0xaf, 0x9a, 0x10, 0x00, 0xb5, 0x02, 0x48, 0xfa, 0xf7, 0xba, 0xf8, +0x08, 0xbc, 0x18, 0x47, 0xb4, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, +0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, +0x22, 0x4d, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, +0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, +0x1d, 0x48, 0xfa, 0xf7, 0x9f, 0xf8, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, +0x01, 0x30, 0x88, 0x61, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, +0x00, 0x28, 0x1f, 0xd0, 0x19, 0x48, 0xfa, 0xf7, 0x91, 0xf8, 0x19, 0x48, +0xfa, 0xf7, 0x8e, 0xf8, 0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, +0x02, 0xd0, 0x16, 0x48, 0xfa, 0xf7, 0x86, 0xf8, 0x01, 0x21, 0x09, 0x04, +0x20, 0x68, 0x01, 0x40, 0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, +0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, +0x01, 0xe0, 0x28, 0x64, 0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0xdd, 0xfc, +0x0b, 0x48, 0xfa, 0xf7, 0x6f, 0xf8, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, -0xb0, 0xb5, 0x24, 0x4f, 0x01, 0x21, 0x09, 0x04, 0x38, 0x68, 0x01, 0x40, -0x06, 0x20, 0x22, 0x4d, 0x22, 0x4c, 0x00, 0x29, 0x05, 0xd1, 0x39, 0x68, -0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xe8, 0x60, -0x00, 0xe0, 0x20, 0x64, 0x03, 0x20, 0xfe, 0xf7, 0xc5, 0xfa, 0xfb, 0xf7, -0xa1, 0xf9, 0x01, 0x23, 0x18, 0x43, 0xfb, 0xf7, 0x6b, 0xfa, 0x00, 0xf0, -0x31, 0xf8, 0x01, 0x21, 0x09, 0x04, 0x38, 0x68, 0x01, 0x40, 0x07, 0x20, -0x00, 0x29, 0x05, 0xd1, 0x39, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, -0x89, 0x0a, 0x01, 0xd3, 0xe8, 0x60, 0x00, 0xe0, 0x20, 0x64, 0x00, 0xf0, -0x89, 0xf8, 0x00, 0xf0, 0x69, 0xf8, 0x00, 0xf0, 0xd3, 0xf8, 0x01, 0x21, -0x09, 0x04, 0x38, 0x68, 0x01, 0x40, 0x09, 0x20, 0x00, 0x29, 0x05, 0xd1, -0x39, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, 0x89, 0x0a, 0x01, 0xd3, -0xe8, 0x60, 0x00, 0xe0, 0x20, 0x64, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, -0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, -0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x21, 0x48, 0xfa, 0xf7, 0x14, 0xfd, -0xfd, 0xf7, 0x4a, 0xf8, 0x00, 0xf0, 0xa6, 0xf8, 0xfd, 0xf7, 0x58, 0xf8, -0x00, 0xf0, 0xc0, 0xf8, 0xfc, 0xf7, 0x9f, 0xfc, 0xff, 0xf7, 0x5c, 0xfd, -0xfd, 0xf7, 0x3c, 0xfa, 0xfd, 0xf7, 0xc4, 0xf9, 0xfd, 0xf7, 0xdc, 0xfa, -0xfd, 0xf7, 0x60, 0xf9, 0xfd, 0xf7, 0x1a, 0xf9, -0xfd, 0xf7, 0xa2, 0xf9, 0x00, 0xf0, 0x8a, 0xf9, 0xfd, 0xf7, 0xb6, 0xfb, -0xfd, 0xf7, 0x24, 0xfb, 0xfd, 0xf7, 0xec, 0xfa, 0xfd, 0xf7, 0x46, 0xf8, -0xfa, 0xf7, 0xf2, 0xfb, 0xff, 0xf7, 0x18, 0xfd, 0x00, 0x20, 0xff, 0xf7, -0xef, 0xfd, 0x00, 0xf0, 0x29, 0xf8, 0x00, 0x20, 0x0a, 0x49, 0x71, 0x23, -0x5b, 0x01, 0xca, 0x18, 0x10, 0x71, 0x50, 0x71, 0x07, 0x23, 0x5b, 0x02, -0xc9, 0x18, 0xc8, 0x62, 0x06, 0x49, 0xc0, 0x46, 0x48, 0x62, 0x00, 0xf0, -0x87, 0xf9, 0x05, 0x48, 0xfa, 0xf7, 0xd6, 0xfc, 0x08, 0xbc, 0x18, 0x47, -0xff, 0xb8, 0x21, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x00, -0x31, 0x98, 0x21, 0x40, 0x00, 0xb5, 0x04, 0x48, 0xfa, 0xf7, 0xc8, 0xfc, -0xfd, 0xf7, 0x7c, 0xfb, 0xfd, 0xf7, 0x34, 0xf8, 0x08, 0xbc, 0x18, 0x47, -0x11, 0xa2, 0x21, 0x40, 0x00, 0xb5, 0xfd, 0xf7, 0x81, 0xfa, 0x06, 0x48, -0xfa, 0xf7, 0xba, 0xfc, 0xfd, 0xf7, 0x56, 0xfa, 0xfd, 0xf7, 0x8c, 0xfb, -0xfd, 0xf7, 0x9e, 0xfb, 0xfd, 0xf7, 0xac, 0xfb, 0x08, 0xbc, 0x18, 0x47, -0x91, 0x03, 0xff, 0xff, 0xf8, 0xb5, 0x1a, 0x48, 0xc1, 0x6b, 0xff, 0x29, -0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x0d, 0x1c, 0x16, 0x1c, 0x17, 0x4c, -0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43, -0x1f, 0x04, 0xa1, 0x61, 0xf8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x38, 0x61, -0x11, 0x4a, 0x12, 0x49, 0x64, 0x20, 0xfa, 0xf7, 0x95, 0xfc, 0x11, 0x4a, -0xc0, 0x46, 0x00, 0x92, 0x10, 0x4b, 0x00, 0x20, 0x29, 0x1c, 0x32, 0x1c, -0xfa, 0xf7, 0x94, 0xfc, 0x0e, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1, -0x10, 0x23, 0x60, 0x69, 0x98, 0x43, 0x60, 0x61, 0xf8, 0x60, 0x01, 0x20, -0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x70, 0xf8, 0xbc, 0x08, 0xbc, -0x18, 0x47, 0x00, 0x00, 0x00, 0x01, 0x18, 0x40, 0xe8, 0x0d, 0x00, 0x80, -0xa0, 0x54, 0xff, 0xff, 0x11, 0xc8, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, -0x44, 0x80, 0x20, 0x40, 0x40, 0x01, 0x18, 0x40, 0xfa, 0x21, 0x03, 0x48, -0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, -0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69, 0x07, 0x4b, 0x19, 0x43, -0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, -0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x70, 0x47, 0x00, 0x00, -0xe8, 0x0d, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10, 0xf0, 0xb4, 0x4b, 0x4a, -0x4b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x4b, 0x4d, 0x4b, 0x4b, 0x98, 0x42, -0x02, 0xd0, 0x01, 0x33, 0x98, 0x42, 0x01, 0xd1, 0x01, 0x20, 0x28, 0x80, -0x01, 0x21, 0xc9, 0x03, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0x61, 0x61, -0x28, 0x88, 0x40, 0x04, 0x44, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x06, 0x20, -0xaf, 0x60, 0x43, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x20, 0x20, 0xc8, 0x23, -0x43, 0x43, 0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3e, 0x4e, 0xc0, 0x46, -0x31, 0x61, 0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3b, 0x4e, 0xc0, 0x46, -0xf3, 0x61, 0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, -0x81, 0x42, 0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, -0x41, 0x1e, 0x34, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, -0x02, 0x38, 0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, -0x06, 0xe0, 0x2e, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, -0x88, 0x42, 0xd2, 0xd9, 0x2b, 0x49, 0x00, 0x20, -0x63, 0x69, 0x9b, 0x08, 0x07, 0xd0, 0x2a, 0x4b, 0x87, 0x00, 0xcb, 0x51, -0x67, 0x69, 0xbf, 0x08, 0x01, 0x30, 0x87, 0x42, 0xf8, 0xd8, 0x24, 0x49, -0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89, 0x58, 0x20, 0x60, 0x43, 0x87, 0x18, -0x00, 0x20, 0x00, 0x22, 0x00, 0x2c, 0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, -0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, -0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc, 0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, -0x00, 0x19, 0x40, 0x01, 0xc7, 0x19, 0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, -0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01, 0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, -0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, -0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69, 0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, -0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51, 0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, -0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00, 0x08, 0x18, 0x04, 0x38, 0x28, 0x61, -0xf0, 0xbc, 0x70, 0x47, 0xb8, 0xce, 0x21, 0x40, 0x00, 0x00, 0x18, 0x40, -0xe8, 0x0d, 0x00, 0x80, 0x02, 0x99, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, -0xc8, 0x29, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00, +0x04, 0x02, 0xff, 0xff, 0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, +0xf4, 0x01, 0xff, 0xff, 0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, +0xe9, 0xaf, 0x21, 0x40, 0x00, 0xb5, 0x16, 0x49, 0x01, 0x22, 0x12, 0x04, +0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68, +0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x10, 0x49, +0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x0f, 0x49, 0xc0, 0x46, 0x08, 0x64, +0x03, 0x20, 0xfe, 0xf7, 0x55, 0xf9, 0xfa, 0xf7, +0x9d, 0xfc, 0x01, 0x23, 0x18, 0x43, 0xfa, 0xf7, 0x77, 0xfd, 0xff, 0xf7, +0xd7, 0xfe, 0xff, 0xf7, 0x5b, 0xfe, 0xff, 0xf7, 0x4b, 0xff, 0xff, 0xf7, +0x5f, 0xff, 0xff, 0xf7, 0xf1, 0xfd, 0xff, 0xf7, 0x77, 0xff, 0x08, 0xbc, +0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, +0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03, +0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88, +0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60, +0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43, +0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61, +0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61, +0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42, +0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e, +0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38, +0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0, +0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42, +0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0, +0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30, +0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89, +0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c, +0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30, +0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc, +0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19, +0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01, +0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, +0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69, +0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51, +0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00, +0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, +0xec, 0xd6, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, +0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00, 0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, -0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x61, 0x01, 0x20, 0x00, 0x06, -0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, +0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06, +0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18, -0x5a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61, +0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61, 0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05, 0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20, 0x40, 0x03, 0x81, 0x61, -0x80, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb5, 0xff, 0xf7, +0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8, 0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xfb, 0x18, -0x5a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3, 0x04, 0x48, 0x01, 0x22, -0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, -0xe8, 0x0d, 0x00, 0x80, 0x91, 0x3d, 0xff, 0xff, 0x00, 0xb5, 0x02, 0x48, -0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xa8, 0x61, 0x00, 0x00, -0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b, 0xa1, 0x21, 0x49, 0x03, -0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c, 0x59, 0x69, 0x53, 0x01, -0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43, 0x87, 0x61, 0xd1, 0x60, -0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x18, 0x1c, -0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43, 0x47, 0x61, 0xd7, 0x60, -0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, -0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c, 0x03, 0x01, 0x1d, 0x19, -0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x5d, 0x6a, 0xbd, 0x42, 0x05, 0xd1, -0xdd, 0x6a, 0x95, 0x42, 0x02, 0xd1, 0x9b, 0x6a, 0x8b, 0x42, 0x1c, 0xd0, -0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20, 0x03, 0x01, 0x1d, 0x19, -0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x5b, 0x6a, 0x00, 0x2b, 0x09, 0xd1, -0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0xda, 0x62, -0x99, 0x62, 0x1a, 0x63, 0x5f, 0x62, 0x02, 0xe0, +0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3, 0x04, 0x48, 0x01, 0x22, +0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc, +0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x09, 0x3e, 0xff, 0xff, +0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47, +0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b, +0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c, +0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43, +0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc, +0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43, +0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00, +0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c, +0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a, +0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a, +0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20, +0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a, +0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01, +0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0, 0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20, -0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, +0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0, 0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01, -0xe3, 0x18, 0x5b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19, -0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x53, 0x6a, 0xc0, 0x46, 0x53, 0x61, -0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61, 0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, -0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28, -0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x5a, 0x68, 0x8a, 0x42, -0x03, 0xd1, 0x00, 0x21, 0x59, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, -0xc0, 0x43, 0xfa, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x68, 0x1b, 0x00, 0x80, +0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19, +0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61, +0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62, +0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28, +0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42, +0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, +0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80, 0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69, 0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01, -0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc3, 0x6a, 0xc0, 0x46, -0x03, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61, -0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0xe8, 0x0d, 0x00, 0x80, +0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46, +0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61, +0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69, 0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a, 0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47, @@ -4100,9 +4288,9 @@ 0x08, 0xc9, 0x08, 0xc0, 0x12, 0x1f, 0xfb, 0xd2, 0x0a, 0xe0, 0x08, 0xc9, 0x03, 0x70, 0x1b, 0x0a, 0x43, 0x70, 0x1b, 0x0a, 0x83, 0x70, 0x1b, 0x0a, 0xc3, 0x70, 0x00, 0x1d, 0x12, 0x1f, 0xf4, 0xd2, 0xd2, 0x1c, 0x05, 0xd3, -0x0b, 0x78, 0x03, 0x70, 0x49, 0x1c, 0x40, 0x1c, 0x52, 0x1e, 0xf9, 0xd2, -0x60, 0x46, 0x70, 0x47, 0x03, 0x1c, 0x0b, 0x43, 0x13, 0x43, 0x9b, 0x07, -0x04, 0xd1, 0x12, 0x1f, 0x8b, 0x58, 0x83, 0x50, 0xfb, 0xd1, 0x70, 0x47, -0x52, 0x1e, 0x8b, 0x5c, 0x83, 0x54, 0xfb, 0xd1, 0x70, 0x47, 0x00, 0x00, -0x00, 0x20, 0x70, 0x47, +0x0b, 0x78, 0x03, 0x70, 0x49, 0x1c, 0x40, 0x1c, +0x52, 0x1e, 0xf9, 0xd2, 0x60, 0x46, 0x70, 0x47, 0x03, 0x1c, 0x0b, 0x43, +0x13, 0x43, 0x9b, 0x07, 0x04, 0xd1, 0x12, 0x1f, 0x8b, 0x58, 0x83, 0x50, +0xfb, 0xd1, 0x70, 0x47, 0x52, 0x1e, 0x8b, 0x5c, 0x83, 0x54, 0xfb, 0xd1, +0x70, 0x47, 0x00, 0x00, 0x00, 0x20, 0x70, 0x47, }; diff -urN linux-2.4.25/drivers/net/typhoon.c linux-2.4.26/drivers/net/typhoon.c --- linux-2.4.25/drivers/net/typhoon.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/typhoon.c 2004-04-14 06:05:30.000000000 -0700 @@ -85,8 +85,8 @@ #define PKT_BUF_SZ 1536 #define DRV_MODULE_NAME "typhoon" -#define DRV_MODULE_VERSION "1.4.2" -#define DRV_MODULE_RELDATE "03/11/25" +#define DRV_MODULE_VERSION "1.4.3" +#define DRV_MODULE_RELDATE "03/12/15" #define PFX DRV_MODULE_NAME ": " #define ERR_PFX KERN_ERR PFX @@ -157,6 +157,7 @@ TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR, TYPHOON_SVR95, TYPHOON_SVR97, TYPHOON_TXM, TYPHOON_BSVR, TYPHOON_FX95, TYPHOON_FX97, TYPHOON_FX95SVR, TYPHOON_FX97SVR, + TYPHOON_FXM, }; /* directly indexed by enum typhoon_cards, above */ @@ -185,6 +186,8 @@ TYPHOON_CRYPTO_DES | TYPHOON_FIBER}, { "3Com Typhoon (3CR990-FX-97 Server)", TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER}, + { "3Com Typhoon2 (3C990B-FX-97)", + TYPHOON_CRYPTO_VARIABLE | TYPHOON_FIBER}, }; /* Notes on the new subsystem numbering scheme: @@ -203,6 +206,8 @@ { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, PCI_ANY_ID, 0x1000, 0, 0, TYPHOON_TXM }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, + PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FXM }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, PCI_ANY_ID, 0x2000, 0, 0, TYPHOON_BSVR }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX, PCI_ANY_ID, 0x1101, 0, 0, TYPHOON_FX95 }, @@ -1363,6 +1368,7 @@ u32 section_len; u32 len; u32 load_addr; + u32 hmac; int i; int err; @@ -1406,6 +1412,16 @@ writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS); writel(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR); + hmac = le32_to_cpu(fHdr->hmacDigest[0]); + writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_0); + hmac = le32_to_cpu(fHdr->hmacDigest[1]); + writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_1); + hmac = le32_to_cpu(fHdr->hmacDigest[2]); + writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_2); + hmac = le32_to_cpu(fHdr->hmacDigest[3]); + writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_3); + hmac = le32_to_cpu(fHdr->hmacDigest[4]); + writel(hmac, ioaddr + TYPHOON_REG_DOWNLOAD_HMAC_4); typhoon_post_pci_writes(ioaddr); writel(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND); diff -urN linux-2.4.25/drivers/net/typhoon.h linux-2.4.26/drivers/net/typhoon.h --- linux-2.4.25/drivers/net/typhoon.h 2003-06-13 07:51:35.000000000 -0700 +++ linux-2.4.26/drivers/net/typhoon.h 2004-04-14 06:05:30.000000000 -0700 @@ -512,6 +512,7 @@ u32 version; u32 numSections; u32 startAddr; + u32 hmacDigest[5]; } __attribute__ ((packed)); struct typhoon_section_header { @@ -548,6 +549,11 @@ #define TYPHOON_REG_BOOT_LENGTH TYPHOON_REG_HOST2ARM1 #define TYPHOON_REG_DOWNLOAD_BOOT_ADDR TYPHOON_REG_HOST2ARM1 +#define TYPHOON_REG_DOWNLOAD_HMAC_0 TYPHOON_REG_HOST2ARM2 +#define TYPHOON_REG_DOWNLOAD_HMAC_1 TYPHOON_REG_HOST2ARM3 +#define TYPHOON_REG_DOWNLOAD_HMAC_2 TYPHOON_REG_HOST2ARM4 +#define TYPHOON_REG_DOWNLOAD_HMAC_3 TYPHOON_REG_HOST2ARM5 +#define TYPHOON_REG_DOWNLOAD_HMAC_4 TYPHOON_REG_HOST2ARM6 #define TYPHOON_REG_BOOT_RECORD_ADDR_HI TYPHOON_REG_HOST2ARM2 #define TYPHOON_REG_BOOT_RECORD_ADDR_LO TYPHOON_REG_HOST2ARM1 diff -urN linux-2.4.25/drivers/net/wireless/Config.in linux-2.4.26/drivers/net/wireless/Config.in --- linux-2.4.25/drivers/net/wireless/Config.in 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/wireless/Config.in 2004-04-14 06:05:30.000000000 -0700 @@ -24,6 +24,7 @@ dep_tristate ' Hermes PCMCIA card support' CONFIG_PCMCIA_HERMES $CONFIG_HERMES tristate ' Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards' CONFIG_AIRO_CS + dep_tristate ' Atmel at76c502/at76c504 PCMCIA cards' CONFIG_PCMCIA_ATMEL $CONFIG_FW_LOADER fi # yes, this works even when no drivers are selected diff -urN linux-2.4.25/drivers/net/wireless/Makefile linux-2.4.26/drivers/net/wireless/Makefile --- linux-2.4.25/drivers/net/wireless/Makefile 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/net/wireless/Makefile 2004-04-14 06:05:30.000000000 -0700 @@ -12,7 +12,7 @@ obj- := # Things that need to export symbols -export-objs := airo.o orinoco.o hermes.o +export-objs := airo.o orinoco.o hermes.o atmel.o obj-$(CONFIG_HERMES) += orinoco.o hermes.o obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o @@ -23,5 +23,6 @@ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o +obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.25/drivers/net/wireless/airo.c linux-2.4.26/drivers/net/wireless/airo.c --- linux-2.4.25/drivers/net/wireless/airo.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/net/wireless/airo.c 2004-04-14 06:05:30.000000000 -0700 @@ -18,7 +18,6 @@ ======================================================================*/ #include -#include #include #include @@ -41,12 +40,11 @@ #include #include #include -#include #include #include #ifdef CONFIG_PCI -static struct pci_device_id card_ids[] __devinitdata = { +static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, @@ -60,10 +58,10 @@ static void airo_pci_remove(struct pci_dev *); static struct pci_driver airo_driver = { - name: "airo", - id_table: card_ids, - probe: airo_pci_probe, - remove: __devexit_p(airo_pci_remove), + .name = "airo", + .id_table = card_ids, + .probe = airo_pci_probe, + .remove = __devexit_p(airo_pci_remove), }; #endif /* CONFIG_PCI */ @@ -202,12 +200,6 @@ #ifndef RUN_AT #define RUN_AT(x) (jiffies+(x)) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) -static inline struct proc_dir_entry *PDE(const struct inode *inode) -{ - return inode->u.generic_ip; -} -#endif /* These variables are for insmod, since it seems that the rates @@ -982,7 +974,7 @@ static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket); static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket); -static void airo_interrupt( int irq, void* dev_id, struct pt_regs +static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs *regs); static int airo_thread(void *data); static void timer_func( struct net_device *dev ); @@ -1034,6 +1026,7 @@ #define FLAG_802_11 7 #define FLAG_PENDING_XMIT 9 #define FLAG_PENDING_XMIT11 10 +#define FLAG_PCI 11 #define JOB_MASK 0x1ff0000 #define JOB_DIE 16 #define JOB_XMIT 17 @@ -2077,7 +2070,7 @@ unregister_netdev( dev ); if (ai->wifidev) { unregister_netdev(ai->wifidev); - kfree(ai->wifidev); + free_netdev(ai->wifidev); ai->wifidev = 0; } ai->registered = 0; @@ -2098,7 +2091,7 @@ crypto_free_tfm(ai->tfm); #endif del_airo_dev( dev ); - kfree( dev ); + free_netdev( dev ); } EXPORT_SYMBOL(stop_airo_card); @@ -2447,20 +2440,23 @@ complete_and_exit (&ai->thr_exited, 0); } -static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) { +static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; u16 status; u16 fid; struct airo_info *apriv = dev->priv; u16 savedInterrupts = 0; + int handled = 0; if (!netif_device_present(dev)) - return; + return IRQ_NONE; for (;;) { status = IN4500( apriv, EVSTAT ); if ( !(status & STATUS_INTS) || status == 0xffff ) break; + handled = 1; + if ( status & EV_AWAKE ) { OUT4500( apriv, EVACK, EV_AWAKE ); OUT4500( apriv, EVACK, EV_AWAKE ); @@ -2790,7 +2786,7 @@ OUT4500( apriv, EVINTEN, savedInterrupts ); /* done.. */ - return; + return IRQ_RETVAL(handled); } /* @@ -3476,56 +3472,56 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ); static struct file_operations proc_statsdelta_ops = { - read: proc_read, - open: proc_statsdelta_open, - release: proc_close + .read = proc_read, + .open = proc_statsdelta_open, + .release = proc_close }; static struct file_operations proc_stats_ops = { - read: proc_read, - open: proc_stats_open, - release: proc_close + .read = proc_read, + .open = proc_stats_open, + .release = proc_close }; static struct file_operations proc_status_ops = { - read: proc_read, - open: proc_status_open, - release: proc_close + .read = proc_read, + .open = proc_status_open, + .release = proc_close }; static struct file_operations proc_SSID_ops = { - read: proc_read, - write: proc_write, - open: proc_SSID_open, - release: proc_close + .read = proc_read, + .write = proc_write, + .open = proc_SSID_open, + .release = proc_close }; static struct file_operations proc_BSSList_ops = { - read: proc_read, - write: proc_write, - open: proc_BSSList_open, - release: proc_close + .read = proc_read, + .write = proc_write, + .open = proc_BSSList_open, + .release = proc_close }; static struct file_operations proc_APList_ops = { - read: proc_read, - write: proc_write, - open: proc_APList_open, - release: proc_close + .read = proc_read, + .write = proc_write, + .open = proc_APList_open, + .release = proc_close }; static struct file_operations proc_config_ops = { - read: proc_read, - write: proc_write, - open: proc_config_open, - release: proc_close + .read = proc_read, + .write = proc_write, + .open = proc_config_open, + .release = proc_close }; static struct file_operations proc_wepkey_ops = { - read: proc_read, - write: proc_write, - open: proc_wepkey_open, - release: proc_close + .read = proc_read, + .write = proc_write, + .open = proc_wepkey_open, + .release = proc_close }; static struct proc_dir_entry *airo_entry = 0; @@ -3553,6 +3549,7 @@ airo_entry); apriv->proc_entry->uid = proc_uid; apriv->proc_entry->gid = proc_gid; + apriv->proc_entry->owner = THIS_MODULE; /* Setup the StatsDelta */ entry = create_proc_entry("StatsDelta", @@ -3561,6 +3558,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ @@ -3570,6 +3568,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ @@ -3579,6 +3578,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ @@ -3588,6 +3588,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ @@ -3597,6 +3598,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ @@ -3606,6 +3608,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ @@ -3615,6 +3618,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ @@ -3624,6 +3628,7 @@ entry->uid = proc_uid; entry->gid = proc_gid; entry->data = dev; + entry->owner = THIS_MODULE; SETPROC_OPS(entry, proc_wepkey_ops); return 0; @@ -3714,8 +3719,6 @@ StatusRid status_rid; int i; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -3795,8 +3798,6 @@ StatsRid stats; int i, j; int *vals = stats.vals; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -4064,8 +4065,6 @@ struct airo_info *ai = dev->priv; int i; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -4337,8 +4336,6 @@ int j=0; int rc; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -4387,8 +4384,6 @@ char *ptr; SsidRid SSID_rid; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -4433,8 +4428,6 @@ char *ptr; APListRid APList_rid; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -4485,8 +4478,6 @@ /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; - MOD_INC_USE_COUNT; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; memset(file->private_data, 0, sizeof(struct proc_data)); @@ -4549,7 +4540,6 @@ { struct proc_data *data = (struct proc_data *)file->private_data; if ( data->on_close != NULL ) data->on_close( inode, file ); - MOD_DEC_USE_COUNT; if ( data->rbuffer ) kfree( data->rbuffer ); if ( data->wbuffer ) kfree( data->wbuffer ); kfree( data ); @@ -4638,6 +4628,7 @@ return -ENODEV; pci_set_drvdata(pdev, dev); + set_bit (FLAG_PCI, &((struct airo_info *)dev->priv)->flags); return 0; } @@ -4667,7 +4658,7 @@ #ifdef CONFIG_PCI printk( KERN_INFO "airo: Probing for PCI adapters\n" ); - pci_register_driver(&airo_driver); + pci_module_init(&airo_driver); /* FIXME: check return val */ printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); #endif @@ -4679,15 +4670,22 @@ static void __exit airo_cleanup_module( void ) { + int is_pci = 0; while( airo_devices ) { printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); +#ifdef CONFIG_PCI + if (test_bit(FLAG_PCI, &((struct airo_info *)airo_devices->dev->priv)->flags)) + is_pci = 1; +#endif stop_airo_card( airo_devices->dev, 1 ); } remove_proc_entry("aironet", proc_root_driver); + if (is_pci) { #ifdef CONFIG_PCI - pci_unregister_driver(&airo_driver); + pci_unregister_driver(&airo_driver); #endif + } } #ifdef WIRELESS_EXT @@ -6183,16 +6181,17 @@ static const struct iw_handler_def airo_handler_def = { - num_standard: sizeof(airo_handler)/sizeof(iw_handler), - num_private: sizeof(airo_private_handler)/sizeof(iw_handler), - num_private_args: sizeof(airo_private_args)/sizeof(struct iw_priv_args), - standard: (iw_handler *) airo_handler, - private: (iw_handler *) airo_private_handler, - private_args: (struct iw_priv_args *) airo_private_args, + .num_standard = sizeof(airo_handler)/sizeof(iw_handler), + .num_private = sizeof(airo_private_handler)/sizeof(iw_handler), + .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) airo_handler, + .private = (iw_handler *) airo_private_handler, + .private_args = (struct iw_priv_args *) airo_private_args, #if WIRELESS_EXT > 15 - spy_offset: ((void *) (&((struct airo_info *) NULL)->spy_data) - + .spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) - (void *) NULL), #endif /* WIRELESS_EXT > 15 */ + }; #endif /* WIRELESS_EXT > 12 */ diff -urN linux-2.4.25/drivers/net/wireless/atmel.c linux-2.4.26/drivers/net/wireless/atmel.c --- linux-2.4.25/drivers/net/wireless/atmel.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/net/wireless/atmel.c 2004-04-14 06:05:30.000000000 -0700 @@ -0,0 +1,3926 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds and the Linux wireless + extensions, (C) Jean Tourrilhes. + + The firmware module for reading the MAC address of the card comes from + net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright + by him. net.russotto.AtmelMACFW is used under the GPL license version 2. + This file contains the module in binary form and, under the terms + of the GPL, in source form. The source is located at the end of the file. + + For all queries about this code, please contact the current author, + Simon Kelley and not Atmel Corporation. + + 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 software 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 Atmel wireless lan drivers; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ieee802_11.h" + +#define DRIVER_MAJOR 0 +#define DRIVER_MINOR 8 + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); + +/* The name of the firmware file to be loaded + over-rides any automatic selection */ +static char *firmware = NULL; + +#define MAX_SSID_LENGTH 32 +#define MGMT_JIFFIES (256 * HZ / 100) + +#define MAX_BSS_ENTRIES 64 + +/* registers */ +#define GCR 0x00 // (SIR0) General Configuration Register +#define BSR 0x02 // (SIR1) Bank Switching Select Register +#define AR 0x04 +#define DR 0x08 +#define MR1 0x12 // Mirror Register 1 +#define MR2 0x14 // Mirror Register 2 +#define MR3 0x16 // Mirror Register 3 +#define MR4 0x18 // Mirror Register 4 + +#define GPR1 0x0c +#define GPR2 0x0e +#define GPR3 0x10 +// +// Constants for the GCR register. +// +#define GCR_REMAP 0x0400 // Remap internal SRAM to 0 +#define GCR_SWRES 0x0080 // BIU reset (ARM and PAI are NOT reset) +#define GCR_CORES 0x0060 // Core Reset (ARM and PAI are reset) +#define GCR_ENINT 0x0002 // Enable Interrupts +#define GCR_ACKINT 0x0008 // Acknowledge Interrupts + +#define BSS_SRAM 0x0200 // AMBA module selection --> SRAM +#define BSS_IRAM 0x0100 // AMBA module selection --> IRAM +// +// Constants for the MR registers. +// +#define MAC_INIT_COMPLETE 0x0001 // MAC init has been completed +#define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed +#define MAC_INIT_OK 0x0002 // MAC boot has been completed + +#define C80211_SUBTYPE_MGMT_ASS_REQUEST 0x00 +#define C80211_SUBTYPE_MGMT_ASS_RESPONSE 0x10 +#define C80211_SUBTYPE_MGMT_REASS_REQUEST 0x20 +#define C80211_SUBTYPE_MGMT_REASS_RESPONSE 0x30 +#define C80211_SUBTYPE_MGMT_ProbeRequest 0x40 +#define C80211_SUBTYPE_MGMT_ProbeResponse 0x50 +#define C80211_SUBTYPE_MGMT_BEACON 0x80 +#define C80211_SUBTYPE_MGMT_ATIM 0x90 +#define C80211_SUBTYPE_MGMT_DISASSOSIATION 0xA0 +#define C80211_SUBTYPE_MGMT_Authentication 0xB0 +#define C80211_SUBTYPE_MGMT_Deauthentication 0xC0 + +#define C80211_MGMT_AAN_OPENSYSTEM 0x0000 +#define C80211_MGMT_AAN_SHAREDKEY 0x0001 + +#define C80211_MGMT_CAPABILITY_ESS 0x0001 // see 802.11 p.58 +#define C80211_MGMT_CAPABILITY_IBSS 0x0002 // - " - +#define C80211_MGMT_CAPABILITY_CFPollable 0x0004 // - " - +#define C80211_MGMT_CAPABILITY_CFPollRequest 0x0008 // - " - +#define C80211_MGMT_CAPABILITY_Privacy 0x0010 // - " - + +#define C80211_MGMT_SC_Success 0 +#define C80211_MGMT_SC_Unspecified 1 +#define C80211_MGMT_SC_SupportCapabilities 10 +#define C80211_MGMT_SC_ReassDenied 11 +#define C80211_MGMT_SC_AssDenied 12 +#define C80211_MGMT_SC_AuthAlgNotSupported 13 +#define C80211_MGMT_SC_AuthTransSeqNumError 14 +#define C80211_MGMT_SC_AuthRejectChallenge 15 +#define C80211_MGMT_SC_AuthRejectTimeout 16 +#define C80211_MGMT_SC_AssDeniedHandleAP 17 +#define C80211_MGMT_SC_AssDeniedBSSRate 18 + +#define C80211_MGMT_ElementID_SSID 0 +#define C80211_MGMT_ElementID_SupportedRates 1 +#define C80211_MGMT_ElementID_ChallengeText 16 +#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020 + +struct get_set_mib { + u8 type; + u8 size; + u8 index; + u8 reserved; + u8 data[72]; +}; + +struct rx_desc { + u32 Next; + u16 MsduPos; + u16 MsduSize; + + u8 State; + u8 Status; + u8 Rate; + u8 Rssi; + u8 LinkQuality; + u8 PreambleType; + u16 Duration; + u32 RxTime; + +}; + +#define RX_DESC_FLAG_VALID 0x80 +#define RX_DESC_FLAG_CONSUMED 0x40 +#define RX_DESC_FLAG_IDLE 0x00 + +#define RX_STATUS_SUCCESS 0x00 + +#define RX_DESC_MSDU_POS_OFFSET 4 +#define RX_DESC_MSDU_SIZE_OFFSET 6 +#define RX_DESC_FLAGS_OFFSET 8 +#define RX_DESC_STATUS_OFFSET 9 +#define RX_DESC_RSSI_OFFSET 11 +#define RX_DESC_LINK_QUALITY_OFFSET 12 +#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 +#define RX_DESC_DURATION_OFFSET 14 +#define RX_DESC_RX_TIME_OFFSET 16 + + +struct tx_desc { + u32 NextDescriptor; + u16 TxStartOfFrame; + u16 TxLength; + + u8 TxState; + u8 TxStatus; + u8 RetryCount; + + u8 TxRate; + u32 TxTime; + u8 Reserved; + u8 PacketType; + u16 HostTxLength; + +}; + + +#define TX_DESC_NEXT_OFFSET 0 +#define TX_DESC_POS_OFFSET 4 +#define TX_DESC_SIZE_OFFSET 6 +#define TX_DESC_FLAGS_OFFSET 8 +#define TX_DESC_STATUS_OFFSET 9 +#define TX_DESC_RETRY_OFFSET 10 +#define TX_DESC_RATE_OFFSET 11 +#define TX_DESC_PACKET_TYPE_OFFSET 17 +#define TX_DESC_HOST_LENGTH_OFFSET 18 + + + +/////////////////////////////////////////////////////// +// Host-MAC interface +/////////////////////////////////////////////////////// + +#define TX_STATUS_SUCCESS 0x00 + +#define TX_FIRM_OWN 0x80 +#define TX_DONE 0x40 + + +#define TX_ERROR 0x01 + +#define TX_PACKET_TYPE_DATA 0x01 +#define TX_PACKET_TYPE_MGMT 0x02 + +#define ISR_EMPTY 0x00 // no bits set in ISR +#define ISR_TxCOMPLETE 0x01 // packet transmitted +#define ISR_RxCOMPLETE 0x02 // packet received +#define ISR_RxFRAMELOST 0x04 // Rx Frame lost +#define ISR_FATAL_ERROR 0x08 // Fatal error +#define ISR_COMMAND_COMPLETE 0x10 // command completed +#define ISR_OUT_OF_RANGE 0x20 // command completed +#define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge +#define ISR_GENERIC_IRQ 0x80 + + +#define Local_Mib_Type 0x01 +#define Mac_Address_Mib_Type 0x02 +#define Mac_Mib_Type 0x03 +#define Statistics_Mib_Type 0x04 +#define Mac_Mgmt_Mib_Type 0x05 +#define Mac_Wep_Mib_Type 0x06 +#define Phy_Mib_Type 0x07 +#define Multi_Domain_MIB 0x08 + +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MIB_FRAG_THRESHOLD_POS 8 +#define MAC_MIB_RTS_THRESHOLD_POS 10 +#define MAC_MIB_SHORT_RETRY_POS 16 +#define MAC_MIB_LONG_RETRY_POS 17 +#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 +#define MAC_MGMT_MIB_BEACON_PER_POS 0 +#define MAC_MGMT_MIB_STATION_ID_POS 6 +#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MGMT_MIB_PS_MODE_POS 53 +#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 +#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 +#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 +#define PHY_MIB_CHANNEL_POS 14 +#define PHY_MIB_RATE_SET_POS 20 +#define PHY_MIB_REG_DOMAIN_POS 26 +#define LOCAL_MIB_AUTO_TX_RATE_POS 3 +#define LOCAL_MIB_SSID_SIZE 5 +#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 +#define LOCAL_MIB_TX_MGMT_RATE_POS 7 +#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 +#define LOCAL_MIB_PREAMBLE_TYPE 9 +#define MAC_ADDR_MIB_MAC_ADDR_POS 0 + + +#define CMD_Set_MIB_Vars 0x01 +#define CMD_Get_MIB_Vars 0x02 +#define CMD_Scan 0x03 +#define CMD_Join 0x04 +#define CMD_Start 0x05 +#define CMD_EnableRadio 0x06 +#define CMD_DisableRadio 0x07 +#define CMD_SiteSurvey 0x0B + +#define CMD_STATUS_IDLE 0x00 +#define CMD_STATUS_COMPLETE 0x01 +#define CMD_STATUS_UNKNOWN 0x02 +#define CMD_STATUS_INVALID_PARAMETER 0x03 +#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 +#define CMD_STATUS_TIME_OUT 0x07 +#define CMD_STATUS_IN_PROGRESS 0x08 +#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 +#define CMD_STATUS_HOST_ERROR 0xFF +#define CMD_STATUS_BUSY 0xFE + + +#define CMD_BLOCK_COMMAND_OFFSET 0 +#define CMD_BLOCK_STATUS_OFFSET 1 +#define CMD_BLOCK_PARAMETERS_OFFSET 4 + +#define SCAN_OPTIONS_SITE_SURVEY 0x80 + +#define MGMT_FRAME_BODY_OFFSET 24 +#define MAX_AUTHENTICATION_RETRIES 3 +#define MAX_ASSOCIATION_RETRIES 3 + +#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 + +#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ +#define LOOP_RETRY_LIMIT 500000 + +#define ACTIVE_MODE 1 +#define PS_MODE 2 + +/////////////////////////////////////////////////////////////////////////// +// 802.11 related definitions +/////////////////////////////////////////////////////////////////////////// + +// +// Regulatory Domains +// + +#define REG_DOMAIN_FCC 0x10 //Channels 1-11 USA +#define REG_DOMAIN_DOC 0x20 //Channel 1-11 Canada +#define REG_DOMAIN_ETSI 0x30 //Channel 1-13 Europe (ex Spain/France) +#define REG_DOMAIN_SPAIN 0x31 //Channel 10-11 Spain +#define REG_DOMAIN_FRANCE 0x32 //Channel 10-13 France +#define REG_DOMAIN_MKK 0x40 //Channel 14 Japan +#define REG_DOMAIN_MKK1 0x41 //Channel 1-14 Japan(MKK1) +#define REG_DOMAIN_ISRAEL 0x50 //Channel 3-9 ISRAEL + +#define BSS_TYPE_AD_HOC 1 +#define BSS_TYPE_INFRASTRUCTURE 2 + +#define SCAN_TYPE_ACTIVE 0 +#define SCAN_TYPE_PASSIVE 1 + +#define LONG_PREAMBLE 0 +#define SHORT_PREAMBLE 1 +#define AUTO_PREAMBLE 2 + +#define DATA_FRAME_WS_HEADER_SIZE 30 + +/* promiscuous mode control */ +#define PROM_MODE_OFF 0x0 +#define PROM_MODE_UNKNOWN 0x1 +#define PROM_MODE_CRC_FAILED 0x2 +#define PROM_MODE_DUPLICATED 0x4 +#define PROM_MODE_MGMT 0x8 +#define PROM_MODE_CTRL 0x10 +#define PROM_MODE_BAD_PROTOCOL 0x20 + + +#define IFACE_INT_STATUS_OFFSET 0 +#define IFACE_INT_MASK_OFFSET 1 +#define IFACE_LOCKOUT_HOST_OFFSET 2 +#define IFACE_LOCKOUT_MAC_OFFSET 3 +#define IFACE_FUNC_CTRL_OFFSET 28 +#define IFACE_MAC_STAT_OFFSET 30 +#define IFACE_GENERIC_INT_TYPE_OFFSET 32 +// +// IFACE MACROS & definitions +// +// + +// FuncCtrl field: +// +#define FUNC_CTRL_TxENABLE 0x10 +#define FUNC_CTRL_RxENABLE 0x20 +#define FUNC_CTRL_INIT_COMPLETE 0x01 + +/* A stub firmware image which reads the MAC address from NVRAM on the card. + For copyright information and source see the end of this file. */ +static u8 mac_reader[] = { + 0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea, + 0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, + 0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5, + 0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5, + 0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1, + 0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb, + 0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb, + 0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5, + 0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea, + 0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2, + 0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3, + 0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3, + 0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5, + 0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5, + 0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5, + 0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3, + 0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5, + 0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5, + 0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1, + 0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2, + 0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb, + 0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb, + 0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3, + 0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5, + 0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3, + 0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a, + 0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3, + 0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2, + 0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb, + 0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02, + 0x00,0x01,0x00,0x02 +}; + +struct atmel_private { + void *card; /* Bus dependent stucture varies for PCcard */ + int (*present_callback)(void *); /* And callback which uses it */ + char firmware_id[32]; + unsigned char *firmware; + int firmware_length; + struct timer_list management_timer; + struct net_device *dev; + struct iw_statistics wstats; + struct net_device_stats stats; // device stats + spinlock_t irqlock, timerlock; // spinlocks + enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; + enum { + CARD_TYPE_PARALLEL_FLASH, + CARD_TYPE_SPI_FLASH, + CARD_TYPE_EEPROM + } card_type; + int is3com; /* is this a 3com card? they are uniquely borken */ + int do_rx_crc; /* If we need to CRC incoming packets */ + int probe_crc; /* set if we don't yet know */ + int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ + u16 rx_desc_head; + u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; + u16 tx_free_mem, tx_buff_head, tx_buff_tail; + + u16 frag_seq, frag_len, frag_no; + u8 frag_source[6]; + + int wep_key_len[4]; /* need to know these and not stored in Mib. */ + struct { /* NB this is matched to the hardware, don't change. */ + u8 wep_is_on; + u8 default_key; /* 0..3 */ + u8 reserved; + u8 exclude_unencrypted; + + u32 WEPICV_error_count; + u32 WEP_excluded_count; + + u8 wep_keys[4][13]; + u8 encryption_level; /* 0, 1, 2 */ + u8 reserved2[3]; + } wep; + + u16 host_info_base; + struct host_info_struct { + /* NB this is matched to the hardware, don't change. */ + u8 volatile int_status; + u8 volatile int_mask; + u8 volatile lockout_host; + u8 volatile lockout_mac; + + u16 tx_buff_pos; + u16 tx_buff_size; + u16 tx_desc_pos; + u16 tx_desc_count; + + u16 rx_buff_pos; + u16 rx_buff_size; + u16 rx_desc_pos; + u16 rx_desc_count; + + u16 build_version; + u16 command_pos; + + u16 major_version; + u16 minor_version; + + u16 func_ctrl; + u16 mac_status; + u16 generic_IRQ_type; + u8 reserved[2]; + } host_info; + + enum { + STATION_STATE_INITIALIZING, + STATION_STATE_SCANNING, + STATION_STATE_JOINNING, + STATION_STATE_AUTHENTICATING, + STATION_STATE_ASSOCIATING, + STATION_STATE_READY, + STATION_STATE_REASSOCIATING, + STATION_STATE_FORCED_JOINNING, + STATION_STATE_FORCED_JOIN_FAILURE, + STATION_STATE_DOWN, + STATION_STATE_NO_CARD, + STATION_STATE_MGMT_ERROR + } station_state; + + int operating_mode, power_mode; + time_t last_qual; + int beacons_this_sec; + int channel; + int reg_domain; + int tx_rate; + int auto_tx_rate;; + int rts_threshold; + int frag_threshold; + int long_retry, short_retry; + int preamble; + int default_beacon_period, beacon_period, listen_interval; + int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; + int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; + enum { + SITE_SURVEY_IDLE, + SITE_SURVEY_IN_PROGRESS, + SITE_SURVEY_COMPLETED + } site_survey_state; + time_t last_survey; + + int station_was_associated, station_is_associated; + int fast_scan; + + struct bss_info { + int channel; + int SSIDsize; + int RSSI; + int UsingWEP; + int preamble; + int beacon_period; + int BSStype; + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + } BSSinfo[MAX_BSS_ENTRIES]; + int BSS_list_entries, current_BSS; + int connect_to_any_BSS; + int SSID_size, new_SSID_size; + u8 CurrentBSSID[6], BSSID[6]; + u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; + u64 last_beacon_timestamp; + u8 rx_buf[MAX_WIRELESS_BODY]; + +}; + +static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len); +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len); +static void atmel_set_gcr(struct net_device *dev, u16 mask); +static void atmel_clear_gcr(struct net_device *dev, u16 mask); +static int atmel_lock_mac(struct atmel_private *priv); +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); +static void atmel_command_irq(struct atmel_private *priv); +static int atmel_validate_channel(struct atmel_private *priv, int channel); +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi); +static void atmel_management_timer(u_long a); +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u8 *body, int body_len); + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data); +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data); +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_scan(struct atmel_private *priv, int specific_ssid); +static void atmel_join_bss(struct atmel_private *priv, int bss_index); +static void atmel_smooth_qual(struct atmel_private *priv); +static void atmel_writeAR(struct net_device *dev, u16 data); +static int probe_atmel_card(struct net_device *dev); +int reset_atmel_card(struct net_device *dev ); +static void atmel_enter_state(struct atmel_private *priv, int new_state); + +static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) +{ + return priv->host_info_base + offset; +} + +static inline u16 atmel_co(struct atmel_private *priv, u16 offset) +{ + return priv->host_info.command_pos + offset; +} + +static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; +} + +static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; +} + +static inline u8 atmel_read8(struct net_device *dev, u16 offset) +{ + return inb(dev->base_addr + offset); +} + +static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) +{ + outb(data, dev->base_addr + offset); +} + +static inline u16 atmel_read16(struct net_device *dev, u16 offset) +{ + return inw(dev->base_addr + offset); +} + +static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) +{ + outw(data, dev->base_addr + offset); +} + + +static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read8(priv->dev, DR); +} + +static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write8(priv->dev, DR, data); +} + +static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read16(priv->dev, DR); +} + +static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); +} + +static const struct iw_handler_def atmel_handler_def; + +static void tx_done_irq(struct atmel_private *priv) +{ + int i; + + for (i = 0; + atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && + i < priv->host_info.tx_desc_count; + i++) { + + u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); + u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); + u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); + + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); + + priv->tx_free_mem += msdu_size; + priv->tx_desc_free++; + + if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) + priv->tx_buff_head = 0; + else + priv->tx_buff_head += msdu_size; + + if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) + priv->tx_desc_head++ ; + else + priv->tx_desc_head = 0; + + if (type == TX_PACKET_TYPE_DATA) { + if (status == TX_STATUS_SUCCESS) + priv->stats.tx_packets++; + else + priv->stats.tx_errors++; + netif_wake_queue(priv->dev); + } + } +} + +static u16 find_tx_buff(struct atmel_private *priv, u16 len) +{ + u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; + + if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) + return 0; + + if (bottom_free >= len) + return priv->host_info.tx_buff_pos + priv->tx_buff_tail; + + if (priv->tx_free_mem - bottom_free >= len) { + priv->tx_buff_tail = 0; + return priv->host_info.tx_buff_pos; + } + + return 0; +} + +static void tx_update_descriptor(struct atmel_private *priv, u16 len, u16 buff, u8 type) +{ + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); + if (priv->tx_desc_previous != priv->tx_desc_tail) + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); + priv->tx_desc_previous = priv->tx_desc_tail; + if (priv->tx_desc_tail < (priv->host_info.tx_desc_count -1 )) + priv->tx_desc_tail++; + else + priv->tx_desc_tail = 0; + priv->tx_desc_free--; + priv->tx_free_mem -= len; + +} + +static int start_tx (struct sk_buff *skb, struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct ieee802_11_hdr header; + unsigned long flags; + u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + + if(priv->station_state != STATION_STATE_READY) { + priv->stats.tx_errors++; + return 0; + } + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) { + priv->stats.tx_errors++; + return 0; + } + + /* first ensure the timer func cannot run */ + spin_lock_bh(&priv->timerlock); + /* then stop the hardware ISR */ + spin_lock_irqsave(&priv->irqlock, flags); + /* nb doing the above in the opposite order will deadlock */ + + /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the + 12 first bytes (containing DA/SA) and put them in the appropriate fields of + the Wireless Header. Thus the packet length is then the initial + 18 (+30-12) */ + + if (!(buff = find_tx_buff(priv, len + 18))) { + priv->stats.tx_dropped++; + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + netif_stop_queue(dev); + return 1; + } + + frame_ctl = IEEE802_11_FTYPE_DATA; + header.duration_id = 0; + header.seq_ctl = 0; + if (priv->wep.wep_is_on) + frame_ctl |= IEEE802_11_FCTL_WEP; + if (priv->operating_mode == IW_MODE_ADHOC) { + memcpy(&header.addr1, skb->data, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, priv->BSSID, 6); + } else { + frame_ctl |= IEEE802_11_FCTL_TODS; + memcpy(&header.addr1, priv->CurrentBSSID, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, skb->data, 6); + } + + header.frame_ctl = cpu_to_le16(frame_ctl); + /* Copy the wireless header into the card */ + atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); + /* Copy the packet sans its 802.3 header addresses which have been replaced */ + atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); + priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; + + tx_update_descriptor(priv, len + 18, buff, TX_PACKET_TYPE_DATA); + dev->trans_start = jiffies; + priv->stats.tx_bytes += len; + + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + dev_kfree_skb(skb); + + return 0; +} + +static void atmel_transmit_management_frame(struct atmel_private *priv, + struct ieee802_11_hdr *header, + u8 *body, int body_len) +{ + u16 buff; + int len = MGMT_FRAME_BODY_OFFSET + body_len; + + if (!(buff = find_tx_buff(priv, len))) + return; + + atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); + atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); + priv->tx_buff_tail += len; + tx_update_descriptor(priv, len, buff, TX_PACKET_TYPE_MGMT); +} + +static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc) +{ + /* fast path: unfragmented packet copy directly into skbuf */ + u8 mac4[6]; + struct sk_buff *skb; + unsigned char *skbp; + + /* get the final, mac 4 header field, this tells us encapsulation */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); + msdu_size -= 6; + + if (priv->do_rx_crc) { + crc = crc32_le(crc, mac4, 6); + msdu_size -= 4; + } + + if (!(skb = dev_alloc_skb(msdu_size + 14))) { + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, 2); + skbp = skb_put(skb, msdu_size + 12); + atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, skbp + 12, msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + dev_kfree_skb(skb); + return; + } + } + + memcpy(skbp, header->addr1, 6); /* destination address */ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(&skbp[6], header->addr3, 6); + else + memcpy(&skbp[6], header->addr2, 6); /* source address */ + + priv->dev->last_rx=jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += 12 + msdu_size; + priv->stats.rx_packets++; +} + +/* Test to see if the packet in card memory at packet_loc has a valid CRC + It doesn't matter that this is slow: it is only used to proble the first few packets. */ +static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) +{ + int i = msdu_size - 4; + u32 netcrc, crc = 0xffffffff; + + if (msdu_size < 4) + return 0; + + atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); + + atmel_writeAR(priv->dev, packet_loc); + while (i--) { + u8 octet = atmel_read8(priv->dev, DR); + crc = crc32_le(crc, &octet, 1); + } + + return (crc ^ 0xffffffff) == netcrc; +} + +static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) +{ + u8 mac4[6]; + u8 source[6]; + struct sk_buff *skb; + + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(source, header->addr3, 6); + else + memcpy(source, header->addr2, 6); + + rx_packet_loc += 24; /* skip header */ + + if (priv->do_rx_crc) + msdu_size -= 4; + + if (frag_no == 0) { /* first fragment */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); + msdu_size -= 6; + rx_packet_loc += 6; + + if (priv->do_rx_crc) + crc = crc32_le(crc, mac4, 6); + + priv->frag_seq = seq_no; + priv->frag_no = 1; + priv->frag_len = msdu_size; + memcpy(priv->frag_source, source, 6); + memcpy(&priv->rx_buf[6], source, 6); + memcpy(priv->rx_buf, header->addr1, 6); + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + } + } + + } else if (priv->frag_no == frag_no && + priv->frag_seq == seq_no && + memcmp(priv->frag_source, source, 6) == 0) { + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], + rx_packet_loc, msdu_size); + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, + &priv->rx_buf[12 + priv->frag_len], + msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + more_frags = 1; /* don't send broken assembly */ + } + } + + priv->frag_len += msdu_size; + priv->frag_no++; + + if (!more_frags) { /* last one */ + memset(priv->frag_source, 0xff, 6); + if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { + priv->stats.rx_dropped++; + } else { + skb_reserve(skb, 2); + memcpy(skb_put(skb, priv->frag_len + 12), + priv->rx_buf, + priv->frag_len + 12); + priv->dev->last_rx = jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += priv->frag_len + 12; + priv->stats.rx_packets++; + } + } + + } else + priv->wstats.discard.fragment++; +} + +static void rx_done_irq(struct atmel_private *priv) +{ + int i; + struct ieee802_11_hdr header; + + for (i = 0; + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && + i < priv->host_info.rx_desc_count; + i++) { + + u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; + u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); + u32 crc = 0xffffffff; + + if (status != RX_STATUS_SUCCESS) { + if (status == 0xc1) /* determined by experiment */ + priv->wstats.discard.nwid++; + else + priv->stats.rx_errors++; + goto next; + } + + msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); + rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); + + if (msdu_size < 30) { + priv->stats.rx_errors++; + goto next; + } + + /* Get header as far as end of seq_ctl */ + atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); + frame_ctl = le16_to_cpu(header.frame_ctl); + seq_control = le16_to_cpu(header.seq_ctl); + + /* probe for CRC use here if needed once five packets have arrived with + the same crc status, we assume we know what's happening and stop probing */ + if (priv->probe_crc) { + if (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); + } else { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); + } + if (priv->do_rx_crc) { + if (priv->crc_ok_cnt++ > 5) + priv->probe_crc = 0; + } else { + if (priv->crc_ko_cnt++ > 5) + priv->probe_crc = 0; + } + } + + /* don't CRC header when WEP in use */ + if (priv->do_rx_crc && (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { + crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); + } + msdu_size -= 24; /* header */ + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { + + int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; + u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; + u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; + + if (!more_fragments && packet_fragment_no == 0 ) { + fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); + } else { + frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, + packet_sequence_no, packet_fragment_no, more_fragments); + } + } + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { + /* copy rest of packet into buffer */ + atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); + + /* we use the same buffer for frag reassembly and control packets */ + memset(priv->frag_source, 0xff, 6); + + if (priv->do_rx_crc) { + /* last 4 octets is crc */ + msdu_size -= 4; + crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); + if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { + priv->stats.rx_crc_errors++; + goto next; + } + } + + atmel_management_frame(priv, &header, msdu_size, + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); + } + + next: + /* release descriptor */ + atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); + + if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) + priv->rx_desc_head++; + else + priv->rx_desc_head = 0; + } +} + +static void reset_irq_status(struct atmel_private *priv, u8 mask) +{ + u8 isr; + + atmel_lock_mac(priv); + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + isr ^= mask; + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); +} + +static void service_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + u8 isr; + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + + while (1) { + if (!atmel_lock_mac(priv)) { + printk(KERN_ALERT "%s: MAC gone away in ISR.\n", dev->name); + /* bad things - don't re-enable interrupts */ + return; + } + + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (isr) + atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ + else + break; /* no pending irqs */ + + if (isr & ISR_OUT_OF_RANGE) { + reset_irq_status(priv, ISR_OUT_OF_RANGE); + if(priv->operating_mode == IW_MODE_INFRA && + priv->station_state == STATION_STATE_READY) { + priv->station_is_associated = 0; + atmel_scan(priv, 1); + } + } else if (isr & ISR_RxCOMPLETE) { + reset_irq_status(priv, ISR_RxCOMPLETE); + rx_done_irq(priv); + } else if (isr & ISR_TxCOMPLETE) { + reset_irq_status(priv, ISR_TxCOMPLETE); + tx_done_irq(priv); + } else if (isr & ISR_RxFRAMELOST) { + reset_irq_status(priv, ISR_RxFRAMELOST); + priv->wstats.discard.misc++; + rx_done_irq(priv); + } else if (isr & ISR_FATAL_ERROR) { + reset_irq_status(priv, ISR_FATAL_ERROR); + printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + } else if (isr & ISR_COMMAND_COMPLETE) { + reset_irq_status(priv, ISR_COMMAND_COMPLETE); + atmel_command_irq(priv); + } else if (isr & ISR_IBSS_MERGE) { + reset_irq_status(priv, ISR_IBSS_MERGE); + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + priv->CurrentBSSID, 6); + } else if (isr & ISR_GENERIC_IRQ) { + reset_irq_status(priv, ISR_GENERIC_IRQ); + printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name); + } + } + + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return; +} + + +static struct net_device_stats *atmel_get_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + return &priv->stats; +} + +static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + + /* update the link quality here in case we are seeing no beacons + at all to drive the process */ + atmel_smooth_qual(priv); + + priv->wstats.status = priv->station_state; + + if (priv->operating_mode == IW_MODE_INFRA) { + if (priv->station_state != STATION_STATE_READY) { + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + } + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 7; + } else { + // Quality levels cannot be determined in ad-hoc mode, + // because we can 'hear' more than one remote station. + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 0; + priv->wstats.miss.beacon = 0; + } + + return (&priv->wstats); +} + +static int atmel_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 2312)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static int atmel_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); + reset_atmel_card(dev); + return 0; +} + +static int atmel_open (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + priv->station_state = STATION_STATE_INITIALIZING; + if (!reset_atmel_card(dev)) { + priv->station_state = STATION_STATE_DOWN; + return -EAGAIN; + } + return 0; +} + +static int atmel_close (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + + if (netif_running(dev)) + netif_stop_queue(dev); + + priv->station_state = STATION_STATE_DOWN; + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + return 0; +} + +static int atmel_proc_output (char *buf, struct atmel_private *priv) +{ + char *p = buf; + char *s, *r, *c; + + p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); + + if (priv->station_state != STATION_STATE_DOWN) { + p += sprintf(p, "Firmware version:\t%d.%d build %d ", + priv->host_info.major_version, + priv->host_info.minor_version, + priv->host_info.build_version); + + if (priv->card_type != CARD_TYPE_EEPROM) + p += sprintf(p, "[built-in]\n"); + else if (priv->firmware) + p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id); + else + p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id); + + switch(priv->card_type) { + case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break; + case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break; + case CARD_TYPE_EEPROM: c = "EEPROM"; break; + default: c = ""; + } + + switch (priv->reg_domain) { + case REG_DOMAIN_FCC: r = "USA"; break; + case REG_DOMAIN_DOC: r = "Canada"; break; + case REG_DOMAIN_ETSI: r = "Europe"; break; + case REG_DOMAIN_SPAIN: r = "Spain"; break; + case REG_DOMAIN_FRANCE: r = "France"; break; + case REG_DOMAIN_MKK: r = "Japan (MKK)"; break; + case REG_DOMAIN_MKK1: r = "Japan (MKK1)"; break; + case REG_DOMAIN_ISRAEL: r = "Israel"; break; + default: r = ""; + } + p += sprintf(p, "MAC memory type:\t%s\n", c); + p += sprintf(p, "Regulatory domain:\t%s\n", r); + p += sprintf(p, "Host CRC checking:\t%s\n", + priv->do_rx_crc ? "On" : "Off"); + } + + switch(priv->station_state) { + case STATION_STATE_INITIALIZING: s = "Initialising"; break; + case STATION_STATE_SCANNING: s = "Scanning"; break; + case STATION_STATE_JOINNING: s = "Joining"; break; + case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break; + case STATION_STATE_ASSOCIATING: s = "Associating"; break; + case STATION_STATE_READY: s = "Ready"; break; + case STATION_STATE_REASSOCIATING: s = "Reassociating"; break; + case STATION_STATE_FORCED_JOINNING: s = "Forced joining"; break; + case STATION_STATE_FORCED_JOIN_FAILURE: s = "Forced join failure"; break; + case STATION_STATE_NO_CARD: s = "No card"; break; + case STATION_STATE_MGMT_ERROR: s = "Management error"; break; + case STATION_STATE_DOWN: s = "Down"; break; + default: s = ""; + } + + p += sprintf(p, "Current state:\t\t%s\n", s); + return p - buf; +} + +static int atmel_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct atmel_private *priv = (struct atmel_private *)data; + int len = atmel_proc_output (page, priv); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware_id, int is3com, + int (*card_present)(void *), void *card) +{ + struct net_device *dev; + struct atmel_private *priv; + int rc; + + /* Create the network device object. */ + dev = alloc_etherdev(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); + return NULL; + } + if (dev_alloc_name(dev, dev->name) < 0) { + printk(KERN_ERR "atmel: Couldn't get name!\n"); + goto err_out_free; + } + + priv = dev->priv; + priv->dev = dev; + priv->present_callback = card_present; + priv->card = card; + priv->firmware = NULL; + if (firmware) /* module parameter */ + strcpy(priv->firmware_id, firmware); + else if (firmware_id) /* from PCMCIA card-matching or PCI */ + strcpy(priv->firmware_id, firmware_id); + else + priv->firmware_id[0] = '\0'; + priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; + priv->station_state = STATION_STATE_DOWN; + priv->is3com = is3com; + priv->do_rx_crc = 0; + /* For PCMCIA cards, some chips need CRC, some don't + so we have to probe. */ + if (priv->bus_type == BUS_TYPE_PCCARD) { + priv->probe_crc = 1; + priv->crc_ok_cnt = priv->crc_ko_cnt = 0; + } else + priv->probe_crc = 0; + memset(&priv->stats, 0, sizeof(priv->stats)); + memset(&priv->wstats, 0, sizeof(priv->wstats)); + priv->last_qual = jiffies; + priv->last_beacon_timestamp = 0; + memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); + memset(priv->BSSID, 0, 6); + priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ + priv->station_was_associated = 0; + + priv->last_survey = jiffies; + priv->preamble = LONG_PREAMBLE; + priv->operating_mode = IW_MODE_INFRA; + priv->connect_to_any_BSS = 0; + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + priv->channel = 4; + priv->power_mode = 0; + priv->SSID[0] = '\0'; + priv->SSID_size = 0; + priv->new_SSID_size = 0; + priv->frag_threshold = 2346; + priv->rts_threshold = 2347; + priv->short_retry = 7; + priv->long_retry = 4; + priv->wep.wep_is_on = 0; + priv->wep.default_key = 0; + priv->wep.encryption_level = 0; + priv->default_beacon_period = priv->beacon_period = 100; + priv->listen_interval = 1; + + init_timer(&priv->management_timer); + spin_lock_init(&priv->irqlock); + spin_lock_init(&priv->timerlock); + priv->management_timer.function = atmel_management_timer; + priv->management_timer.data = (unsigned long) dev; + + dev->open = atmel_open; + dev->stop = atmel_close; + dev->change_mtu = atmel_change_mtu; + dev->set_mac_address = atmel_set_mac_address; + dev->hard_start_xmit = start_tx; + dev->get_stats = atmel_get_stats; + dev->get_wireless_stats = atmel_get_wireless_stats; + dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; + dev->do_ioctl = atmel_ioctl; + dev->irq = irq; + dev->base_addr = port; + + if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc ); + goto err_out_free; + } + + if (priv->bus_type == BUS_TYPE_PCI && + !request_region( dev->base_addr, 64, dev->name )) { + goto err_out_irq; + } + + if (register_netdev(dev)) + goto err_out_res; + + if (!probe_atmel_card(dev)) + goto err_out_res; + + create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv); + + printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR); + + SET_MODULE_OWNER(dev); + return dev; + + err_out_res: + if (priv->bus_type == BUS_TYPE_PCI) + release_region( dev->base_addr, 64 ); + err_out_irq: + free_irq(dev->irq, dev); + err_out_free: + kfree(dev); + return NULL; +} + +EXPORT_SYMBOL(init_atmel_card); + +void stop_atmel_card(struct net_device *dev, int freeres) +{ + struct atmel_private *priv = dev->priv; + unregister_netdev(dev); + + /* put a brick on it... */ + + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + + remove_proc_entry("driver/atmel", NULL); + del_timer_sync(&priv->management_timer); + free_irq(dev->irq, dev); + if (priv->firmware) + kfree(priv->firmware); + if (freeres) { + /* PCMCIA frees this stuff, so only for PCI */ + release_region(dev->base_addr, 64); + } + kfree( dev ); +} + +EXPORT_SYMBOL(stop_atmel_card); + +static const struct { + int reg_domain; + int min, max; +} channel_table[] = { { REG_DOMAIN_FCC, 1, 11}, + { REG_DOMAIN_DOC, 1, 11}, + { REG_DOMAIN_ETSI, 1, 13}, + { REG_DOMAIN_SPAIN, 10, 11}, + { REG_DOMAIN_FRANCE, 10, 13}, + { REG_DOMAIN_MKK, 14, 14}, + { REG_DOMAIN_MKK1, 1, 14}, + { REG_DOMAIN_ISRAEL, 9} }; + + +static int atmel_validate_channel(struct atmel_private *priv, int channel) +{ + /* check that channel is OK, if so return zero, + else return suitable default channel */ + int i; + + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) { + if (channel >= channel_table[i].min && + channel <= channel_table[i].max) + return 0; + else + return channel_table[i].min; + } + return 1; +} + +static int atmel_set_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Check if we asked for `any' */ + if(dwrq->flags == 0) { + priv->connect_to_any_BSS = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + priv->connect_to_any_BSS = 0; + + /* Check the size of the string */ + if (dwrq->length > MAX_SSID_LENGTH + 1) + return -E2BIG ; + if (index != 0) + return -EINVAL; + + memcpy(priv->new_SSID, extra, dwrq->length - 1); + priv->new_SSID_size = dwrq->length - 1; + } + + return -EINPROGRESS; +} + +static int atmel_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Get the current SSID */ + if (priv->SSID_size == 0) { + memcpy(extra, priv->new_SSID, priv->new_SSID_size); + extra[priv->new_SSID_size] = '\0'; + dwrq->length = priv->new_SSID_size + 1; + } else { + memcpy(extra, priv->SSID, priv->SSID_size); + extra[priv->SSID_size] = '\0'; + dwrq->length = priv->SSID_size + 1; + } + + dwrq->flags = !priv->connect_to_any_BSS; /* active */ + + return 0; +} + +static int atmel_get_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + memcpy(awrq->sa_data, priv->CurrentBSSID, 6); + awrq->sa_family = ARPHRD_ETHER; + + return 0; +} + +static int atmel_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Basic checking: do we have a key to set ? + * Note : with the new API, it's impossible to get a NULL pointer. + * Therefore, we need to check a key size == 0 instead. + * New version of iwconfig properly set the IW_ENCODE_NOKEY flag + * when no key is present (only change flags), but older versions + * don't do it. - Jean II */ + if (dwrq->length > 0) { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index = priv->wep.default_key; + /* Check the size of the key */ + if (dwrq->length > 13) { + return -EINVAL; + } + /* Check the index (none -> use current) */ + if (index < 0 || index >= 4) + index = current_index; + else + priv->wep.default_key = index; + /* Set the length */ + if (dwrq->length > 5) + priv->wep_key_len[index] = 13; + else + if (dwrq->length > 0) + priv->wep_key_len[index] = 5; + else + /* Disable the key */ + priv->wep_key_len[index] = 0; + /* Check if the key is not marked as invalid */ + if(!(dwrq->flags & IW_ENCODE_NOKEY)) { + /* Cleanup */ + memset(priv->wep.wep_keys[index], 0, 13); + /* Copy the key in the driver */ + memcpy(priv->wep.wep_keys[index], extra, dwrq->length); + } + /* WE specify that if a valid key is set, encryption + * should be enabled (user may turn it off later) + * This is also how "iwconfig ethX key on" works */ + if (index == current_index && + priv->wep_key_len[index] > 0) { + priv->wep.wep_is_on = 1; + priv->wep.exclude_unencrypted = 1; + if (priv->wep_key_len[index] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + } else { + /* Do we want to just set the transmit key index ? */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ( index>=0 && index < 4 ) { + priv->wep.default_key = index; + } else + /* Don't complain if only change the mode */ + if(!dwrq->flags & IW_ENCODE_MODE) { + return -EINVAL; + } + } + /* Read the flags */ + if(dwrq->flags & IW_ENCODE_DISABLED) { + priv->wep.wep_is_on = 0; + priv->wep.encryption_level = 0; + } else { + priv->wep.wep_is_on = 1; + if (priv->wep_key_len[priv->wep.default_key] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + if(dwrq->flags & IW_ENCODE_RESTRICTED) + priv->wep.exclude_unencrypted = 1; + if(dwrq->flags & IW_ENCODE_OPEN) + priv->wep.exclude_unencrypted = 0; + + return -EINPROGRESS; /* Call commit handler */ +} + + +static int atmel_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (!priv->wep.wep_is_on) + dwrq->flags = IW_ENCODE_DISABLED; + else if (priv->wep.exclude_unencrypted) + dwrq->flags = IW_ENCODE_RESTRICTED; + else + dwrq->flags = IW_ENCODE_OPEN; + + /* Which key do we want ? -1 -> tx index */ + if (index < 0 || index >= 4) + index = priv->wep.default_key; + dwrq->flags |= index + 1; + /* Copy the key to the user buffer */ + dwrq->length = priv->wep_key_len[index]; + if (dwrq->length > 16) { + dwrq->length=0; + } else { + memset(extra, 0, 16); + memcpy(extra, priv->wep.wep_keys[index], dwrq->length); + } + + return 0; +} + +static int atmel_get_name(struct net_device *dev, + struct iw_request_info *info, + char *cwrq, + char *extra) +{ + strcpy(cwrq, "IEEE 802.11-DS"); + return 0; +} + +static int atmel_set_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (vwrq->fixed == 0) { + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + } else { + priv->auto_tx_rate = 0; + + /* Which type of value ? */ + if((vwrq->value < 4) && (vwrq->value >= 0)) { + /* Setting by rate index */ + priv->tx_rate = vwrq->value; + } else { + /* Setting by frequency value */ + switch (vwrq->value) { + case (int)1e6: priv->tx_rate = 0; break; + case (int)2e6: priv->tx_rate = 1; break; + case (int)5.5e6: priv->tx_rate = 2; break; + case (int)11e6: priv->tx_rate = 3; break; + default: return -EINVAL; + } + } + } + + return -EINPROGRESS; +} + +static int atmel_set_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) + return -EINVAL; + + priv->operating_mode = *uwrq; + return -EINPROGRESS; +} + +static int atmel_get_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + *uwrq = priv->operating_mode; + return 0; +} + +static int atmel_get_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (priv->auto_tx_rate) { + vwrq->fixed = 0; + vwrq->value = 11e6; + } else { + vwrq->fixed = 1; + switch(priv->tx_rate) { + case 0: vwrq->value = 1e6; break; + case 1: vwrq->value = 2e6; break; + case 2: vwrq->value = 5.5e6; break; + case 3: vwrq->value = 11e6; break; + } + } + return 0; +} + +static int atmel_set_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + priv->power_mode = vwrq->disabled ? 0 : 1; + return -EINPROGRESS; +} + +static int atmel_get_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + vwrq->disabled = priv->power_mode ? 0 : 1; + vwrq->flags = IW_POWER_ON; + return 0; +} + +static int atmel_set_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { + if(vwrq->flags & IW_RETRY_MAX) + priv->long_retry = vwrq->value; + else if (vwrq->flags & IW_RETRY_MIN) + priv->short_retry = vwrq->value; + else { + /* No modifier : set both */ + priv->long_retry = vwrq->value; + priv->short_retry = vwrq->value; + } + return -EINPROGRESS; + } + + return -EINVAL; +} + +static int atmel_get_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the min retry number */ + if((vwrq->flags & IW_RETRY_MAX)) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->value = priv->long_retry; + } else { + vwrq->flags = IW_RETRY_LIMIT; + vwrq->value = priv->short_retry; + if(priv->long_retry != priv->short_retry) + vwrq->flags |= IW_RETRY_MIN; + } + + return 0; +} + +static int atmel_set_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rthr = vwrq->value; + + if(vwrq->disabled) + rthr = 2347; + if((rthr < 0) || (rthr > 2347)) { + return -EINVAL; + } + priv->rts_threshold = rthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->rts_threshold; + vwrq->disabled = (vwrq->value >= 2347); + vwrq->fixed = 1; + + return 0; +} + +static int atmel_set_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int fthr = vwrq->value; + + if(vwrq->disabled) + fthr = 2346; + if((fthr < 256) || (fthr > 2346)) { + return -EINVAL; + } + fthr &= ~0x1; /* Get an even value - is it really needed ??? */ + priv->frag_threshold = fthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->frag_threshold; + vwrq->disabled = (vwrq->value >= 2346); + vwrq->fixed = 1; + + return 0; +} + +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +static int atmel_set_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rc = -EINPROGRESS; /* Call commit handler */ + + /* If setting by frequency, convert to a channel */ + if((fwrq->e == 1) && + (fwrq->m >= (int) 2.412e8) && + (fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + /* Hack to fall through... */ + fwrq->e = 0; + fwrq->m = c + 1; + } + /* Setting by channel number */ + if((fwrq->m > 1000) || (fwrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = fwrq->m; + if (atmel_validate_channel(priv, channel) == 0) { + priv->channel = channel; + } else { + rc = -EINVAL; + } + } + return rc; +} + +static int atmel_get_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + fwrq->m = priv->channel; + fwrq->e = 0; + return 0; +} + +static int atmel_set_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Note : you may have realised that, as this is a SET operation, + * this is privileged and therefore a normal user can't + * perform scanning. + * This is not an error, while the device perform scanning, + * traffic doesn't flow, so it's a perfect DoS... + * Jean II */ + + if (priv->station_state == STATION_STATE_DOWN || + priv->station_state == STATION_STATE_NO_CARD) + return -EAGAIN; + + /* Timeout old surveys. */ + if ((jiffies - priv->last_survey) > (20 * HZ)) + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->last_survey = jiffies; + + /* Initiate a scan command */ + if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) + return -EBUSY; + + priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 0); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + + return 0; +} + +static int atmel_get_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + char *current_ev = extra; + struct iw_event iwe; + + if (priv->site_survey_state != SITE_SURVEY_COMPLETED) + return -EAGAIN; + + for(i=0; iBSS_list_entries; i++) { + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + + iwe.u.data.length = priv->BSSinfo[i].SSIDsize; + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID); + + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = priv->BSSinfo[i].BSStype; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); + + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = priv->BSSinfo[i].channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); + + iwe.cmd = SIOCGIWENCODE; + if (priv->BSSinfo[i].UsingWEP) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); + + } + + /* Length of data */ + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return 0; +} + +static int atmel_get_range(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + struct iw_range *range = (struct iw_range *) extra; + int k,i,j; + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(range)); + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + range->num_channels = 0; + for (j = 0; j < sizeof(channel_table)/sizeof(channel_table[0]); j++) + if (priv->reg_domain == channel_table[j].reg_domain) { + range->num_channels = channel_table[j].max - channel_table[j].min + 1; + break; + } + if (range->num_channels != 0) { + for(k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { + range->freq[k].i = i; /* List index */ + range->freq[k].m = frequency_list[i-1] * 100000; + range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + } + range->num_frequency = k; + } + + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 0; + range->sensitivity = 0; + + range->bitrate[0] = 1e6; + range->bitrate[1] = 2e6; + range->bitrate[2] = 5.5e6; + range->bitrate[3] = 11e6; + range->num_bitrates = 4; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + range->we_version_source = WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + range->retry_capa = IW_RETRY_LIMIT ; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + range->min_retry = 1; + range->max_retry = 65535; + range->avg_qual.qual = 50; + range->avg_qual.level = 50; + range->avg_qual.noise = 0; + + return 0; +} + +static int atmel_set_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + if (memcmp(bcast, awrq->sa_data, 6) == 0) { + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 1); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return 0; + } + + for(i=0; iBSS_list_entries; i++) { + if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { + if (!priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else if (priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else + atmel_join_bss(priv, i); + return 0; + } + } + + return -EINVAL; +} + +static int atmel_config_commit(struct net_device *dev, + struct iw_request_info *info, /* NULL */ + void *zwrq, /* NULL */ + char *extra) /* NULL */ +{ + reset_atmel_card(dev); + return 0; +} + +static const iw_handler atmel_handler[] = +{ + (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) atmel_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ + (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ + (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ + (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_wap, /* SIOCSIWAP */ + (iw_handler) atmel_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ + (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ + (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ + (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ + (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ + (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ + (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ + (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ + (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ + (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ + (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ + (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ + (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ + (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ +}; + + +static const iw_handler atmel_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ +}; + +typedef struct atmel_priv_ioctl { + char id[32]; + unsigned char *data; + unsigned short len; +} atmel_priv_ioctl; + + +#define ATMELFWL SIOCIWFIRSTPRIV +#define ATMELIDIFC ATMELFWL + 1 +#define ATMELMAGIC 0x51807 + +static const struct iw_priv_args atmel_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" }, + { ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" }, +}; + +static const struct iw_handler_def atmel_handler_def = +{ + .num_standard = sizeof(atmel_handler)/sizeof(iw_handler), + .num_private = sizeof(atmel_private_handler)/sizeof(iw_handler), + .num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) atmel_handler, + .private = (iw_handler *) atmel_private_handler, + .private_args = (struct iw_priv_args *) atmel_private_args +}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + atmel_priv_ioctl com; + struct iwreq *wrq = (struct iwreq *) rq; + unsigned char *new_firmware; + + switch (cmd) { + case SIOCGIWPRIV: + if(wrq->u.data.pointer) { + /* Set the number of ioctl available */ + wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]); + + /* Copy structure to the user buffer */ + if (copy_to_user(wrq->u.data.pointer, + (u_char *) atmel_private_args, + sizeof(atmel_private_args))) + rc = -EFAULT; + } + break; + + case ATMELIDIFC: + wrq->u.param.value = ATMELMAGIC; + break; + + case ATMELFWL: + if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { + rc = -EFAULT; + break; + } + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(new_firmware, com.data, com.len)) { + rc = -EFAULT; + break; + } + + if (priv->firmware) + kfree(priv->firmware); + + priv->firmware = new_firmware; + priv->firmware_length = com.len; + strncpy(priv->firmware_id, com.id, 31); + priv->firmware_id[31] = '\0'; + break; + + default: + rc = -EOPNOTSUPP; + } + + return rc; +} + +struct auth_body { + u16 alg; + u16 trans_seq; + u16 status; + u8 el_id; + u8 chall_text_len; + u8 chall_text[253]; +}; + +static void atmel_enter_state(struct atmel_private *priv, int new_state) +{ + int old_state = priv->station_state; + + if (new_state == old_state) + return; + + if (new_state == STATION_STATE_READY) + netif_start_queue(priv->dev); + + if (old_state == STATION_STATE_READY) { + netif_stop_queue(priv->dev); + priv->last_beacon_timestamp = 0; + } + + priv->station_state = new_state; + +} + +static void atmel_scan(struct atmel_private *priv, int specific_ssid) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 scan_type; + u8 channel; + u16 BSS_type; + u16 min_channel_time; + u16 max_channel_time; + u8 options; + u8 SSID_size; + } cmd; + + atmel_enter_state(priv, STATION_STATE_SCANNING); + + memset(cmd.BSSID, 0xff, 6); + + if (priv->fast_scan) { + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(50); + } else { + priv->BSS_list_entries = 0; + cmd.SSID_size = 0; + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(120); + } + + cmd.options = 0; + + if (!specific_ssid) + cmd.options |= SCAN_OPTIONS_SITE_SURVEY; + + cmd.channel = (priv->channel & 0x7f); + cmd.scan_type = SCAN_TYPE_ACTIVE; + cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? + BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); + + atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); +} + +static void join(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; /* this is a short in a scan command - wierd */ + u8 channel; + u16 timeout; + u8 SSID_size; + u8 reserved; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->CurrentBSSID, 6); + cmd.channel = (priv->channel & 0x7f); + cmd.BSS_type = type; + cmd.timeout = cpu_to_le16(2000); + + atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); +} + + +static void start(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; + u8 channel; + u8 SSID_size; + u8 reserved[3]; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->BSSID, 6); + cmd.BSS_type = type; + cmd.channel = (priv->channel & 0x7f); + + atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); +} + +static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) +{ + int rejoin = 0; + int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; + + if (priv->preamble != new) { + priv->preamble = new; + rejoin = 1; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); + } + + if (priv->channel != channel) { + priv->channel = channel; + rejoin = 1; + atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); + } + + if (rejoin) { + priv->station_is_associated = 0; + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); + } +} + + +static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) +{ + struct ieee802_11_hdr header; + struct auth_body auth; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + if (priv->wep.wep_is_on) { + auth.alg = C80211_MGMT_AAN_SHAREDKEY; + /* no WEP for authentication frames with TrSeqNo 1 */ + if (priv->CurrentAuthentTransactionSeqNum != 1) + header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP); + } else { + auth.alg = C80211_MGMT_AAN_OPENSYSTEM; + } + + auth.status = 0; + auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); + priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; + priv->CurrentAuthentTransactionSeqNum += 2; + + if (challenge_len != 0) { + auth.el_id = 16; /* challenge_text */ + auth.chall_text_len = challenge_len; + memcpy(auth.chall_text, challenge, challenge_len); + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); + } else { + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); + } +} + +static void send_association_request(struct atmel_private *priv, int is_reassoc) +{ + u8 *ssid_el_p; + int bodysize; + struct ieee802_11_hdr header; + struct ass_req_format { + u16 capability; + u16 listen_interval; + u8 ap[6]; /* nothing after here directly accessible */ + u8 ssid_el_id; + u8 ssid_len; + u8 ssid[MAX_SSID_LENGTH]; + u8 sup_rates_el_id; + u8 sup_rates_len; + u8 rates[4]; + } body; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | + (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ)); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS); + if (priv->wep.wep_is_on) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy); + if (priv->preamble == SHORT_PREAMBLE) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble); + + body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); + + /* current AP address - only in reassoc frame */ + if (is_reassoc) { + memcpy(body.ap, priv->CurrentBSSID, 6); + ssid_el_p = (u8 *)&body.ssid_el_id; + bodysize = 18 + priv->SSID_size; + } else { + ssid_el_p = (u8 *)&body.ap[0]; + bodysize = 12 + priv->SSID_size; + } + + ssid_el_p[0]= C80211_MGMT_ElementID_SSID; + ssid_el_p[1] = priv->SSID_size; + memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); + ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates; + ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ + memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); + + atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); +} + +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header) +{ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; + else + return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; +} + +static int retrieve_bss(struct atmel_private *priv) +{ + int i; + int max_rssi = -128; + int max_index = -1; + + if (priv->BSS_list_entries == 0) + return -1; + + if (priv->connect_to_any_BSS) { + /* Select a BSS with the max-RSSI but of the same type and of the same WEP mode + and that it is not marked as 'bad' (i.e. we had previously failed to connect to + this BSS with the settings that we currently use) */ + priv->current_BSS = 0; + for(i=0; iBSS_list_entries; i++) { + if (priv->operating_mode == priv->BSSinfo[i].BSStype && + ((!priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) || + (priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP)) && + !(priv->BSSinfo[i].channel & 0x80)) { + max_rssi = priv->BSSinfo[i].RSSI; + priv->current_BSS = max_index = i; + } + + } + return max_index; + } + + for(i=0; iBSS_list_entries; i++) { + if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && + memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && + priv->operating_mode == priv->BSSinfo[i].BSStype && + atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { + if (priv->BSSinfo[i].RSSI >= max_rssi) { + max_rssi = priv->BSSinfo[i].RSSI; + max_index = i; + } + } + } + return max_index; +} + + +static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 capability, u16 beacon_period, u8 channel, u8 rssi, + u8 ssid_len, u8 *ssid, int is_beacon) +{ + u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3; + int i, index; + + for (index = -1, i = 0; i < priv->BSS_list_entries; i++) + if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) + index = i; + + /* If we process a probe and an entry from this BSS exists + we will update the BSS entry with the info from this BSS. + If we process a beacon we will only update RSSI */ + + if (index == -1) { + if (priv->BSS_list_entries == MAX_BSS_ENTRIES) + return; + index = priv->BSS_list_entries++; + memcpy(priv->BSSinfo[index].BSSID, bss, 6); + priv->BSSinfo[index].RSSI = rssi; + } else { + if (rssi > priv->BSSinfo[index].RSSI) + priv->BSSinfo[index].RSSI = rssi; + if (is_beacon) + return; + } + + priv->BSSinfo[index].channel = channel; + priv->BSSinfo[index].beacon_period = beacon_period; + priv->BSSinfo[index].UsingWEP = capability & C80211_MGMT_CAPABILITY_Privacy; + memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); + priv->BSSinfo[index].SSIDsize = ssid_len; + + if (capability & C80211_MGMT_CAPABILITY_IBSS) + priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; + else if (capability & C80211_MGMT_CAPABILITY_ESS) + priv->BSSinfo[index].BSStype =IW_MODE_INFRA; + + priv->BSSinfo[index].preamble = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; +} + +static void authenticate(struct atmel_private *priv, u16 frame_len) +{ + struct auth_body *auth = (struct auth_body *)priv->rx_buf; + u16 status = le16_to_cpu(auth->status); + u16 trans_seq_no = le16_to_cpu(auth->trans_seq); + + if (status == C80211_MGMT_SC_Success && !priv->wep.wep_is_on) { + /* no WEP */ + if (priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + + if (status == C80211_MGMT_SC_Success && priv->wep.wep_is_on) { + /* WEP */ + if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) + return; + + if (trans_seq_no == 0x0002 && + auth->el_id == C80211_MGMT_ElementID_ChallengeText) { + send_authentication_request(priv, auth->chall_text, auth->chall_text_len); + return; + } + + if (trans_seq_no == 0x0004) { + if(priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + } + + if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) { + int bss_index; + + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) { + atmel_join_bss(priv, bss_index); + return; + } + } + + + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; +} + +static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) +{ + struct ass_resp_format { + u16 capability; + u16 status; + u16 ass_id; + u8 el_id; + u8 length; + u8 rates[4]; + } *ass_resp = (struct ass_resp_format *)priv->rx_buf; + + u16 status = le16_to_cpu(ass_resp->status); + u16 ass_id = le16_to_cpu(ass_resp->ass_id); + u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; + + if (frame_len < 8 + rates_len) + return; + + if (status == C80211_MGMT_SC_Success) { + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE) + priv->AssociationRequestRetryCnt = 0; + else + priv->ReAssociationRequestRetryCnt = 0; + + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); + if (priv->power_mode == 0) { + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } else { + priv->listen_interval = 2; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); + } + + priv->station_is_associated = 1; + priv->station_was_associated = 1; + atmel_enter_state(priv, STATION_STATE_READY); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->AssociationRequestRetryCnt++; + send_association_request(priv, 0); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_REASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->ReAssociationRequestRetryCnt++; + send_association_request(priv, 1); + return; + } + + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + + if(priv->connect_to_any_BSS) { + int bss_index; + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + + } +} + +void atmel_join_bss(struct atmel_private *priv, int bss_index) +{ + struct bss_info *bss = &priv->BSSinfo[bss_index]; + + memcpy(priv->CurrentBSSID, bss->BSSID, 6); + memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); + + /* When switching to AdHoc turn OFF Power Save if needed */ + + if (bss->BSStype == IW_MODE_ADHOC && + priv->operating_mode != IW_MODE_ADHOC && + priv->power_mode) { + priv->power_mode = 0; + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } + + priv->operating_mode = bss->BSStype; + priv->channel = bss->channel & 0x7f; + priv->beacon_period = bss->beacon_period; + + if (priv->preamble != bss->preamble) { + priv->preamble = bss->preamble; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); + } + + if (!priv->wep.wep_is_on && bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + if (priv->wep.wep_is_on && !bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); +} + + +static void restart_search(struct atmel_private *priv) +{ + int bss_index; + + if (!priv->connect_to_any_BSS) { + atmel_scan(priv, 1); + } else { + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + else + atmel_scan(priv, 0); + + } +} + +static void smooth_rssi(struct atmel_private *priv, u8 rssi) +{ + u8 old = priv->wstats.qual.level; + + /* 502-rmfd-revd gives max signal level as 42, by experiment. + This is going to break for other hardware variants. */ + + rssi = rssi * 100 / 42; + if((rssi + old) % 2) + priv->wstats.qual.level = ((rssi + old)/2) + 1; + else + priv->wstats.qual.level = ((rssi + old)/2); + +} + +static void atmel_smooth_qual(struct atmel_private *priv) +{ + unsigned long time_diff = (jiffies - priv->last_qual)/HZ; + while (time_diff--) { + priv->last_qual += HZ; + priv->wstats.qual.qual = priv->wstats.qual.qual/2; + priv->wstats.qual.qual += + priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; + priv->beacons_this_sec = 0; + } +} + +/* deals with incoming managment frames. */ +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi) +{ + u16 subtype; + + switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) { + case C80211_SUBTYPE_MGMT_BEACON : + case C80211_SUBTYPE_MGMT_ProbeResponse: + + /* beacon frame has multiple variable-length fields - + never let an engineer loose with a data structure design. */ + { + struct beacon_format { + u64 timestamp; + u16 interval; + u16 capability; + u8 ssid_el_id; + u8 ssid_length; + /* ssid here */ + u8 rates_el_id; + u8 rates_length; + /* rates here */ + u8 ds_el_id; + u8 ds_length; + /* ds here */ + } *beacon = (struct beacon_format *)priv->rx_buf; + + u8 channel, rates_length, ssid_length; + u64 timestamp = le64_to_cpu(beacon->timestamp); + u16 beacon_interval = le16_to_cpu(beacon->interval); + u16 capability = le16_to_cpu(beacon->capability); + u8 *beaconp = priv->rx_buf; + ssid_length = beacon->ssid_length; + /* this blows chunks. */ + if (frame_len < 14 || frame_len < ssid_length + 15) + return; + rates_length = beaconp[beacon->ssid_length + 15]; + if (frame_len < ssid_length + rates_length + 18) + return; + if (ssid_length > MAX_SSID_LENGTH) + return; + channel = beaconp[ssid_length + rates_length + 18]; + + if (priv->station_state == STATION_STATE_READY) { + smooth_rssi(priv, rssi); + if (is_frame_from_current_bss(priv, header)) { + priv->beacons_this_sec++; + atmel_smooth_qual(priv); + if (priv->last_beacon_timestamp) { + /* Note truncate this to 32 bits - kernel can't divide a long long */ + u32 beacon_delay = timestamp - priv->last_beacon_timestamp; + int beacons = beacon_delay / (beacon_interval * 1000); + if (beacons > 1) + priv->wstats.miss.beacon += beacons - 1; + } + priv->last_beacon_timestamp = timestamp; + handle_beacon_probe(priv, capability, channel); + } + } + + if (priv->station_state == STATION_STATE_SCANNING ) + store_bss_info(priv, header, capability, beacon_interval, channel, + rssi, ssid_length, &beacon->rates_el_id, + subtype == C80211_SUBTYPE_MGMT_BEACON) ; + } + break; + + case C80211_SUBTYPE_MGMT_Authentication: + + if (priv->station_state == STATION_STATE_AUTHENTICATING) + authenticate(priv, frame_len); + + break; + + case C80211_SUBTYPE_MGMT_ASS_RESPONSE: + case C80211_SUBTYPE_MGMT_REASS_RESPONSE: + + if (priv->station_state == STATION_STATE_ASSOCIATING || + priv->station_state == STATION_STATE_REASSOCIATING) + associate(priv, frame_len, subtype); + + break; + + case C80211_SUBTYPE_MGMT_DISASSOSIATION: + if (priv->station_is_associated && + priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + priv->station_is_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + + case C80211_SUBTYPE_MGMT_Deauthentication: + if (priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + } +} + +/* run when timer expires */ +static void atmel_management_timer(u_long a) +{ + struct net_device *dev = (struct net_device *) a; + struct atmel_private *priv = (struct atmel_private *)dev->priv; + unsigned long flags; + + /* Check if the card has been yanked. */ + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return; + + if (priv->station_state == STATION_STATE_NO_CARD) + return; + + spin_lock_irqsave(&priv->irqlock, flags); + + switch (priv->station_state) { + + case STATION_STATE_AUTHENTICATING: + + if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AuthenticationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AuthenticationRequestRetryCnt++; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_authentication_request(priv, NULL, 0); + } + + break; + + case STATION_STATE_ASSOCIATING: + + if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 0); + } + + break; + + case STATION_STATE_REASSOCIATING: + + if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->ReAssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->ReAssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 1); + } + + break; + + default: + break; + } + + spin_unlock_irqrestore(&priv->irqlock, flags); +} + +static void atmel_command_irq(struct atmel_private *priv) +{ + u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); + int fast_scan; + + if (status == CMD_STATUS_IDLE || + status == CMD_STATUS_IN_PROGRESS) + return; + + switch (command){ + + case CMD_Start: + if (status == CMD_STATUS_COMPLETE) { + priv->station_was_associated = priv->station_is_associated; + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + (u8 *)priv->CurrentBSSID, 6); + atmel_enter_state(priv, STATION_STATE_READY); + } + break; + + case CMD_Scan: + fast_scan = priv->fast_scan; + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) { + atmel_scan(priv, 1); + } else { + int bss_index = retrieve_bss(priv); + if (bss_index != -1) { + atmel_join_bss(priv, bss_index); + } else if (priv->operating_mode == IW_MODE_ADHOC && + priv->SSID_size != 0) { + start(priv, BSS_TYPE_AD_HOC); + } else { + priv->fast_scan = !fast_scan; + atmel_scan(priv, 1); + } + } + break; + + case CMD_SiteSurvey: + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) + return; + + priv->site_survey_state = SITE_SURVEY_COMPLETED; + if (priv->station_is_associated) { + atmel_enter_state(priv, STATION_STATE_READY); + } else { + atmel_scan(priv, 1); + } + break; + + case CMD_Join: + if (status == CMD_STATUS_COMPLETE) { + if (priv->operating_mode == IW_MODE_ADHOC) { + priv->station_was_associated = priv->station_is_associated; + atmel_enter_state(priv, STATION_STATE_READY); + } else { + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); + + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->CurrentAuthentTransactionSeqNum = 0x0001; + send_authentication_request(priv, NULL, 0); + } + return; + } + + + if (priv->station_state == STATION_STATE_FORCED_JOINNING) { + atmel_enter_state(priv, STATION_STATE_FORCED_JOIN_FAILURE); + } else { + atmel_scan(priv, 1); + } + } +} + +static int atmel_wakeup_firmware(struct atmel_private *priv) +{ + struct host_info_struct *iface = &priv->host_info; + u16 mr1, mr3; + int i; + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + atmel_set_gcr(priv->dev, GCR_REMAP); + + /* wake up on-board processor */ + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(priv->dev, BSR, BSS_SRAM); + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + mdelay(100); + + /* and wait for it */ + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_BOOT_COMPLETE) + break; + if (mr1 & MAC_BOOT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); + return 0; + } + + if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { + printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); + priv->station_state = STATION_STATE_NO_CARD; + return 0; + } + + /* now check for completion of MAC initialization through + the FunCtrl field of the IFACE, poll MR1 to detect completion of + MAC initialization, check completion status, set interrupt mask, + enables interrupts and calls Tx and Rx initialization functions */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_INIT_COMPLETE) + break; + if (mr1 & MAC_INIT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to initialise.\n", priv->dev->name); + return 0; + } + + /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ + if ((mr3 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); + return 0; + } + if ((mr1 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); + return 0; + } + + atmel_copy_to_host(priv->dev, (unsigned char *)iface, + priv->host_info_base, sizeof(*iface)); + + iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); + iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); + iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); + iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); + iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); + iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); + iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); + iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); + iface->build_version = le16_to_cpu(iface->build_version); + iface->command_pos = le16_to_cpu(iface->command_pos); + iface->major_version = le16_to_cpu(iface->major_version); + iface->minor_version = le16_to_cpu(iface->minor_version); + iface->func_ctrl = le16_to_cpu(iface->func_ctrl); + iface->mac_status = le16_to_cpu(iface->mac_status); + + return 1; +} + +/* determine type of memory and MAC address */ +static int probe_atmel_card(struct net_device *dev) +{ + int rc = 0; + struct atmel_private *priv = dev->priv; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + + atmel_write16(dev, GCR, 0x0040); + mdelay(500); + + if (atmel_read16(dev, MR2) == 0) { + /* No stored firmware so load a small stub which just + tells us the MAC address */ + int i; + priv->card_type = CARD_TYPE_EEPROM; + atmel_write16(dev, BSR, BSS_IRAM); + atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); + atmel_set_gcr(dev, GCR_REMAP); + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(dev, BSR, BSS_SRAM); + for (i = LOOP_RETRY_LIMIT; i; i--) + if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) + break; + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); + } else { + atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } else if (atmel_read16(dev, MR4) == 0) { + /* Mac address easy in this case. */ + priv->card_type = CARD_TYPE_PARALLEL_FLASH; + atmel_write16(dev, BSR, 1); + atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); + atmel_write16(dev, BSR, 0x200); + rc = 1; + } else { + /* Standard firmware in flash, boot it up and ask + for the Mac Address */ + priv->card_type = CARD_TYPE_SPI_FLASH; + if (atmel_wakeup_firmware(priv)) { + atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } + + if (rc) { + if (dev->dev_addr[0] == 0xFF) { + u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00}; + printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); + memcpy(dev->dev_addr, default_mac, 6); + } + printk(KERN_INFO "%s: MAC address %x:%x:%x:%x:%x:%x\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + + } + + return rc; +} + +int reset_atmel_card(struct net_device *dev) +{ + /* do everything necessary to wake up the hardware, including + waiting for the lightning strike and throwing the knife switch.... + + set all the Mib values which matter in the card to match + their settings in the atmel_private structure. Some of these + can be altered on the fly, but many (WEP, infrastucture or ad-hoc) + can only be changed by tearing down the world and coming back through + here. + + This routine is also responsible for initialising some + hardware-specific fields in the atmel_private structure, + including a copy of the firmware's hostinfo stucture + which is the route into the rest of the firmare datastructures. */ + + int channel; + struct atmel_private *priv = dev->priv; + u8 configuration; + + if (priv->station_state == STATION_STATE_NO_CARD || + priv->station_state == STATION_STATE_DOWN) + return 0; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(priv->dev, GCR, 0x0060); + + /* stop card , disable interrupts */ + atmel_write16(priv->dev, GCR, 0x0040); + + /* any scheduled timer is no longer needed and might screw things up.. */ + del_timer_sync(&priv->management_timer); + if (priv->new_SSID_size) { + memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); + priv->SSID_size = priv->new_SSID_size; + priv->new_SSID_size = 0; + } + priv->BSS_list_entries = 0; + + priv->AuthenticationRequestRetryCnt = 0; + priv->AssociationRequestRetryCnt = 0; + priv->ReAssociationRequestRetryCnt = 0; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + priv->ExpectedAuthentTransactionSeqNum = 0x0002; + + priv->station_state = STATION_STATE_INITIALIZING; + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->station_is_associated = 0; + + if (priv->card_type == CARD_TYPE_EEPROM) { + /* copy in firmware if needed */ + const struct firmware *fw_entry = NULL; + unsigned char *fw; + int len = priv->firmware_length; + if (!(fw = priv->firmware)) { + if (strlen(priv->firmware_id) == 0) { + printk(KERN_INFO + "%s: card type is unknown: assuming at76c502 firmware is OK.\n", + dev->name); + printk(KERN_INFO + "%s: if not, use the firmware= module parameter.\n", + dev->name); + strcpy(priv->firmware_id, "atmel_at76c502.bin"); + } + if (request_firmware(&fw_entry, priv->firmware_id, "pcmcia") != 0) { + printk(KERN_ALERT + "%s: firmware %s is missing, cannot start.\n", + dev->name, priv->firmware_id); + return 0; + } + fw = fw_entry->data; + len = fw_entry->size; + } + + if (len <= 0x6000) { + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, len); + atmel_set_gcr(priv->dev, GCR_REMAP); + } else { + /* Remap */ + atmel_set_gcr(priv->dev, GCR_REMAP); + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, 0x6000); + atmel_write16(priv->dev, BSR, 0x2ff); + atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); + } + + if (fw_entry) + release_firmware(fw_entry); + } + + if (!atmel_wakeup_firmware(priv)) + return 0; + + /* unmask all irq sources */ + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); + + /* int Tx system and enable Tx */ + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); + + priv->tx_desc_free = priv->host_info.tx_desc_count; + priv->tx_desc_head = 0; + priv->tx_desc_tail = 0; + priv->tx_desc_previous = 0; + priv->tx_free_mem = priv->host_info.tx_buff_size; + priv->tx_buff_head = 0; + priv->tx_buff_tail = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_TxENABLE); + + /* init Rx system and enable */ + priv->rx_desc_head = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_RxENABLE); + + priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); + if (priv->reg_domain != REG_DOMAIN_FCC && + priv->reg_domain != REG_DOMAIN_DOC && + priv->reg_domain != REG_DOMAIN_ETSI && + priv->reg_domain != REG_DOMAIN_SPAIN && + priv->reg_domain != REG_DOMAIN_FRANCE && + priv->reg_domain != REG_DOMAIN_MKK && + priv->reg_domain != REG_DOMAIN_MKK1 && + priv->reg_domain != REG_DOMAIN_ISRAEL) { + priv->reg_domain = REG_DOMAIN_MKK1; + printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); + } + if ((channel = atmel_validate_channel(priv, priv->channel))) + priv->channel = channel; + + if (!priv->is3com) { + if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == + CMD_STATUS_REJECTED_RADIO_OFF) { + printk(KERN_INFO + "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n", + dev->name); + return 0; + } + } + + /* set up enough MIB values to run. */ + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); + atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, + priv->dev->dev_addr, 6); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep.wep_is_on); + atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&priv->wep, sizeof(priv->wep)); + + atmel_scan(priv, 1); + + atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ + + return 1; +} + +EXPORT_SYMBOL(reset_atmel_card); + +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + if (cmd) + atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), + cmd, cmd_size); + + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); +} + +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + int i, status; + + atmel_send_command(priv, command, cmd, cmd_size); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + if (status != CMD_STATUS_IDLE && + status != CMD_STATUS_IN_PROGRESS) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: command %d failed to complete.\n", priv->dev->name, command); + status = CMD_STATUS_HOST_ERROR; + } else { + if (command != CMD_EnableRadio) + status = CMD_STATUS_COMPLETE; + } + + return status; +} + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4)); +} + +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + m.data[0] = data; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 2; + m.index = index; + m.data[0] = data; + m.data[1] = data >> 8; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + memcpy(m.data, data, data_len); + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + atmel_copy_to_host(priv->dev, data, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4), data_len); +} + +static void atmel_writeAR(struct net_device *dev, u16 data) +{ + int i; + outw(data, dev->base_addr + AR); + /* Address register appears to need some convincing..... */ + for (i = 0; data != inw(dev->base_addr + AR) && i<10; i++) + outw(data, dev->base_addr + AR); +} + +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len) +{ + int i; + atmel_writeAR(dev, dest); + if (dest % 2) { + atmel_write8(dev, DR, *src); + src++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u8 lb = *src++; + u8 hb = *src++; + atmel_write16(dev, DR, lb | (hb << 8)); + } + if (i) + atmel_write8(dev, DR, *src); +} + +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len) +{ + int i; + atmel_writeAR(dev, src); + if (src % 2) { + *dest = atmel_read8(dev, DR); + dest++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u16 hw = atmel_read16(dev, DR); + *dest++ = hw; + *dest++ = hw >> 8; + } + if (i) + *dest = atmel_read8(dev, DR); +} + +static void atmel_set_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); +} + +static void atmel_clear_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); +} + +static int atmel_lock_mac(struct atmel_private *priv) +{ + int i, j = 100; + retry: + for (i = LOOP_RETRY_LIMIT ; atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)) && i ; i--); + + if (!i) return 0; /* timed out */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); + if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (!j--) return 0; /* timed out */ + goto retry; + } + + return 1; +} + +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); /* card is little-endian */ + atmel_write16(priv->dev, DR, data >> 16); +} + + +/***************************************************************************/ +/* There follows the source form of the MAC address reading firmware */ +/***************************************************************************/ +#if 0 + +/* Copyright 2003 Matthew T. Russotto */ +/* But derived from the Atmel 76C502 firmware written by Atmel and */ +/* included in "atmel wireless lan drivers" package */ +/** + This file is part of net.russotto.AtmelMACFW, hereto referred to + as AtmelMACFW + + AtmelMACFW is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + AtmelMACFW 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 AtmelMACFW; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +****************************************************************************/ +/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ +/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ +/* It only works on SPI EEPROM versions of the card. */ + +/* This firmware initializes the SPI controller and clock, reads the MAC */ +/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ +/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ +/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ +/* MR4, for investigational purposes (maybe we can determine chip type */ +/* from that?) */ + + .org 0 + .set MRBASE, 0x8000000 + .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ + .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ + .set SRAM_BASE, 0x02000000 + .set SP_BASE, 0x0F300000 + .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ + .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ + .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ + .set STACK_BASE, 0x5600 + .set SP_SR, 0x10 + .set SP_TDRE, 2 /* status register bit -- TDR empty */ + .set SP_RDRF, 1 /* status register bit -- RDR full */ + .set SP_SWRST, 0x80 + .set SP_SPIEN, 0x1 + .set SP_CR, 0 /* control register */ + .set SP_MR, 4 /* mode register */ + .set SP_RDR, 0x08 /* Read Data Register */ + .set SP_TDR, 0x0C /* Transmit Data Register */ + .set SP_CSR0, 0x30 /* chip select registers */ + .set SP_CSR1, 0x34 + .set SP_CSR2, 0x38 + .set SP_CSR3, 0x3C + .set NVRAM_CMD_RDSR, 5 /* read status register */ + .set NVRAM_CMD_READ, 3 /* read data */ + .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ + .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the + serial output, since SO is normally high. But it + does cause 8 clock cycles and thus 8 bits to be + clocked in to the chip. See Atmel's SPI + controller (e.g. AT91M55800) timing and 4K + SPI EEPROM manuals */ + + .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ + .set NVRAM_IMAGE, 0x02000200 + .set NVRAM_LENGTH, 0x0200 + .set MAC_ADDRESS_MIB, SRAM_BASE + .set MAC_ADDRESS_LENGTH, 6 + .set MAC_BOOT_FLAG, 0x10 + .set MR1, 0 + .set MR2, 4 + .set MR3, 8 + .set MR4, 0xC +RESET_VECTOR: + b RESET_HANDLER +UNDEF_VECTOR: + b HALT1 +SWI_VECTOR: + b HALT1 +IABORT_VECTOR: + b HALT1 +DABORT_VECTOR: +RESERVED_VECTOR: + b HALT1 +IRQ_VECTOR: + b HALT1 +FIQ_VECTOR: + b HALT1 +HALT1: b HALT1 +RESET_HANDLER: + mov r0, #CPSR_INITIAL + msr CPSR_c, r0 /* This is probably unnecessary */ + +/* I'm guessing this is initializing clock generator electronics for SPI */ + ldr r0, =SPI_CGEN_BASE + mov r1, #0 + mov r1, r1, lsl #3 + orr r1,r1, #0 + str r1, [r0] + ldr r1, [r0, #28] + bic r1, r1, #16 + str r1, [r0, #28] + mov r1, #1 + str r1, [r0, #8] + + ldr r0, =MRBASE + mov r1, #0 + strh r1, [r0, #MR1] + strh r1, [r0, #MR2] + strh r1, [r0, #MR3] + strh r1, [r0, #MR4] + + mov sp, #STACK_BASE + bl SP_INIT + mov r0, #10 + bl DELAY9 + bl GET_MAC_ADDR + bl GET_WHOLE_NVRAM + ldr r0, =MRBASE + ldr r1, =MAC_ADDRESS_MIB + strh r1, [r0, #MR2] + ldr r1, =NVRAM_IMAGE + strh r1, [r0, #MR4] + mov r1, #MAC_BOOT_FLAG + strh r1, [r0, #MR3] +HALT2: b HALT2 +.func Get_Whole_NVRAM, GET_WHOLE_NVRAM +GET_WHOLE_NVRAM: + stmdb sp!, {lr} + mov r2, #0 /* 0th bytes of NVRAM */ + mov r3, #NVRAM_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =NVRAM_IMAGE + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc + +.func Get_MAC_Addr, GET_MAC_ADDR +GET_MAC_ADDR: + stmdb sp!, {lr} + mov r2, #0x120 /* address of MAC Address within NVRAM */ + mov r3, #MAC_ADDRESS_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =MAC_ADDRESS_MIB + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc +.ltorg +.func Delay9, DELAY9 +DELAY9: + adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ +DELAYLOOP: + beq DELAY9_done + subs r0, r0, #1 + b DELAYLOOP +DELAY9_done: + bx lr +.endfunc + +.func SP_Init, SP_INIT +SP_INIT: + mov r1, #SP_SWRST + ldr r0, =SP_BASE + str r1, [r0, #SP_CR] /* reset the SPI */ + mov r1, #0 + str r1, [r0, #SP_CR] /* release SPI from reset state */ + mov r1, #SP_SPIEN + str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ + str r1, [r0, #SP_CR] /* enable the SPI */ + +/* My guess would be this turns on the SPI clock */ + ldr r3, =SPI_CGEN_BASE + ldr r1, [r3, #28] + orr r1, r1, #0x2000 + str r1, [r3, #28] + + ldr r1, =0x2000c01 + str r1, [r0, #SP_CSR0] + ldr r1, =0x2000201 + str r1, [r0, #SP_CSR1] + str r1, [r0, #SP_CSR2] + str r1, [r0, #SP_CSR3] + ldr r1, [r0, #SP_SR] + ldr r0, [r0, #SP_RDR] + bx lr +.endfunc +.func NVRAM_Init, NVRAM_INIT +NVRAM_INIT: + ldr r1, =SP_BASE + ldr r0, [r1, #SP_RDR] + mov r0, #NVRAM_CMD_RDSR + str r0, [r1, #SP_TDR] +SP_loop1: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop1 + + mov r0, #SPI_8CLOCKS + str r0, [r1, #SP_TDR] +SP_loop2: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop2 + + ldr r0, [r1, #SP_RDR] +SP_loop3: + ldr r0, [r1, #SP_SR] + tst r0, #SP_RDRF + beq SP_loop3 + + ldr r0, [r1, #SP_RDR] + and r0, r0, #255 + bx lr +.endfunc + +.func NVRAM_Xfer, NVRAM_XFER + /* r0 = dest address */ + /* r1 = not used */ + /* r2 = src address within NVRAM */ + /* r3 = length */ +NVRAM_XFER: + stmdb sp!, {r4, r5, lr} + mov r5, r0 /* save r0 (dest address) */ + mov r4, r3 /* save r3 (length) */ + mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ + and r0, r0, #8 + add r0, r0, #NVRAM_CMD_READ + ldr r1, =NVRAM_SCRATCH + strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ + strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ +_local1: + bl NVRAM_INIT + tst r0, #NVRAM_SR_RDY + bne _local1 + mov r0, #20 + bl DELAY9 + mov r2, r4 /* length */ + mov r1, r5 /* dest address */ + mov r0, #2 /* bytes to transfer in command */ + bl NVRAM_XFER2 + ldmia sp!, {r4, r5, lr} + bx lr +.endfunc + +.func NVRAM_Xfer2, NVRAM_XFER2 +NVRAM_XFER2: + stmdb sp!, {r4, r5, r6, lr} + ldr r4, =SP_BASE + mov r3, #0 + cmp r0, #0 + bls _local2 + ldr r5, =NVRAM_SCRATCH +_local4: + ldrb r6, [r5, r3] + str r6, [r4, #SP_TDR] +_local3: + ldr r6, [r4, #SP_SR] + tst r6, #SP_TDRE + beq _local3 + add r3, r3, #1 + cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ + blo _local4 +_local2: + mov r3, #SPI_8CLOCKS + str r3, [r4, #SP_TDR] + ldr r0, [r4, #SP_RDR] +_local5: + ldr r0, [r4, #SP_SR] + tst r0, #SP_RDRF + beq _local5 + ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ + mov r0, #0 + cmp r2, #0 /* r2 is # of bytes to copy in */ + bls _local6 +_local7: + ldr r5, [r4, #SP_SR] + tst r5, #SP_TDRE + beq _local7 + str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ +_local8: + ldr r5, [r4, #SP_SR] + tst r5, #SP_RDRF + beq _local8 + ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ + strb r5, [r1], #1 /* postindexed */ + add r0, r0, #1 + cmp r0, r2 + blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ +_local6: + mov r0, #200 + bl DELAY9 + ldmia sp!, {r4, r5, r6, lr} + bx lr +#endif diff -urN linux-2.4.25/drivers/net/wireless/atmel_cs.c linux-2.4.26/drivers/net/wireless/atmel_cs.c --- linux-2.4.25/drivers/net/wireless/atmel_cs.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/net/wireless/atmel_cs.c 2004-04-14 06:05:30.000000000 -0700 @@ -0,0 +1,733 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds. + + For all queries about this code, please contact the current author, + Simon Kelley and not Atmel Corporation. + + 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 software 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 Atmel wireless lan drivers; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************************************************************************/ + +#include +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static char *version = "$Revision: 1.2 $"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card + insertion and ejection events. They are invoked from the atmel_cs + event handler. +*/ + +struct net_device *init_atmel_card(int, int, char *, int, + int (*present_func)(void *), void * ); +void stop_atmel_card( struct net_device *, int ); +int reset_atmel_card( struct net_device * ); + +static void atmel_config(dev_link_t *link); +static void atmel_release(dev_link_t *link); +static int atmel_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *atmel_attach(void); +static void atmel_detach(dev_link_t *); + +/* + You'll also need to prototype all the functions that will actually + be used to talk to your device. See 'pcmem_cs' for a good example + of a fully self-sufficient driver; the other drivers rely more or + less on other parts of the kernel. +*/ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "atmel_cs"; + +/* + A linked list of "instances" of the atmelnet device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. +*/ + +typedef struct local_info_t { + dev_node_t node; + struct net_device *eth_dev; +} local_info_t; + +/*====================================================================*/ + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + atmel_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + + ======================================================================*/ + +static dev_link_t *atmel_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "atmel_attach()\n"); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + return NULL; + } + memset(link, 0, sizeof(struct dev_link_t)); + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + kfree (link); + return NULL; + } + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &atmel_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + atmel_detach(link); + return NULL; + } + + return link; +} /* atmel_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + + ======================================================================*/ + +static void atmel_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "atmel_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) + atmel_release(link); + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) + kfree(link->priv); + kfree(link); +} + +/*====================================================================== + + atmel_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +/* Call-back function to interrogate PCMCIA-specific information + about the current existance of the card */ +static int card_present(void *arg) +{ + dev_link_t *link = (dev_link_t *)arg; + if (link->state & DEV_SUSPEND) + return 0; + else if (link->state & DEV_PRESENT) + return 1; + + return 0; +} + +/* list of cards we know about and their firmware requirements. + Go either by Manfid or version strings. + Cards not in this list will need a firmware parameter to the module + in all probability. Note that the SMC 2632 V2 and V3 have the same + manfids, so we ignore those and use the version1 strings. */ + +static struct { + int manf, card; + char *ver1; + char *firmware; + char *name; +} card_table[] = { + { 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" }, + { 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" }, + { 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" }, + { 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" }, + { 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" }, + { MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" }, + { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" }, + { 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" }, + { 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" }, + { 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */ + { 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */ + { 0, 0, "BT/Voyager 1020 Laptop Adapter", "atmel_at76c502.bin", "BT Voyager 1020"}, + { 0, 0, "IEEE 802.11b/Wireless LAN PC Card", "atmel_at76c502.bin", "Siemens Gigaset PC Card II" }, + { 0, 0, "CNet/CNWLC 11Mbps Wireless PC Card V-5", "atmel_at76c502e.bin", "CNet CNWLC-811ARL" } +}; + +static void atmel_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int last_fn, last_ret; + u_char buf[64]; + int card_index = -1, done = 0; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "atmel_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = CISTPL_MANFID; + if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + int i; + cistpl_manfid_t *manfid; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + manfid = &(parse.manfid); + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + if (!card_table[i].ver1 && + manfid->manf == card_table[i].manf && + manfid->card == card_table[i].card) { + card_index = i; + done = 1; + } + } + } + + tuple.DesiredTuple = CISTPL_VERS_1; + if (!done && (CardServices(GetFirstTuple, handle, &tuple) == 0)) { + int i, j, k; + cistpl_vers_1_t *ver1; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + ver1 = &(parse.version_1); + + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + for (j = 0; j < ver1->ns; j++) { + char *p = card_table[i].ver1; + char *q = &ver1->str[ver1->ofs[j]]; + if (!p) + goto mismatch; + for (k = 0; k < j; k++) { + while ((*p != '\0') && (*p != '/')) p++; + if (*p == '\0') { + if (*q != '\0') + goto mismatch; + } else + p++; + } + while((*q != '\0') && (*p != '\0') && + (*p != '/') && (*p == *q)) p++, q++; + if (((*p != '\0') && *p != '/') || *q != '\0') + goto mismatch; + } + card_index = i; + break; /* done */ + + mismatch: + j = 0; /* dummy stmt to shut up compiler */ + } + } + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (link->irq.AssignedIRQ == 0) { + printk(KERN_ALERT + "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); + goto cs_failed; + } + + ((local_info_t*)link->priv)->eth_dev = + init_atmel_card(link->irq.AssignedIRQ, + link->io.BasePort1, + card_index == -1 ? NULL : card_table[card_index].firmware, + card_index == -1 ? 0 : (card_table[card_index].manf == MANFID_3COM), + card_present, + link); + if (!((local_info_t*)link->priv)->eth_dev) + goto cs_failed; + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); + dev->node.major = dev->node.minor = 0; + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d", + dev->node.dev_name, + card_index == -1 ? "" : card_table[card_index].name, + card_index == -1 ? "" : " ", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + atmel_release(link); +} + +/*====================================================================== + + After a card is removed, atmel_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + + ======================================================================*/ + +static void atmel_release(dev_link_t *link) +{ + struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; + + DEBUG(0, "atmel_release(0x%p)\n", link); + + /* Unlink the device chain */ + link->dev = NULL; + + if (dev) + stop_atmel_card(dev, 0); + ((local_info_t*)link->priv)->eth_dev = 0; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; +} + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + + ======================================================================*/ + +static int atmel_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *local = link->priv; + + DEBUG(1, "atmel_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + atmel_release(link); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + atmel_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + reset_atmel_card(local->eth_dev); + netif_device_attach(local->eth_dev); + } + break; + } + return 0; +} /* atmel_event */ + +static int atmel_cs_init(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "atmel_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &atmel_attach, &atmel_detach); + return 0; +} + +static void atmel_cs_cleanup(void) +{ + unregister_pcmcia_driver(&dev_info); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + atmel_release(dev_list); + atmel_detach(dev_list); + } +} + +/* + 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. + + In addition: + + 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. + 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. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +module_init(atmel_cs_init); +module_exit(atmel_cs_cleanup); diff -urN linux-2.4.25/drivers/pcmcia/yenta.c linux-2.4.26/drivers/pcmcia/yenta.c --- linux-2.4.25/drivers/pcmcia/yenta.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/pcmcia/yenta.c 2004-04-14 06:05:31.000000000 -0700 @@ -870,6 +870,13 @@ { PD(TI,1420), &ti_ops }, { PD(TI,4410), &ti_ops }, { PD(TI,4451), &ti_ops }, + { PD(TI,1510), &ti_ops }, + { PD(TI,1520), &ti_ops }, + + { PD(ENE,1211), &ti_ops }, + { PD(ENE,1225), &ti_ops }, + { PD(ENE,1410), &ti_ops }, + { PD(ENE,1420), &ti_ops }, { PD(RICOH,RL5C465), &ricoh_ops }, { PD(RICOH,RL5C466), &ricoh_ops }, diff -urN linux-2.4.25/drivers/scsi/advansys.c linux-2.4.26/drivers/scsi/advansys.c --- linux-2.4.25/drivers/scsi/advansys.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.26/drivers/scsi/advansys.c 2004-04-14 06:05:31.000000000 -0700 @@ -5551,7 +5551,7 @@ } } else { ADV_CARR_T *carrp; - int req_cnt; + int req_cnt = 0; adv_req_t *reqp = NULL; int sg_cnt = 0; @@ -9257,8 +9257,6 @@ PCI_DEVFN(ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info), ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info)), offset, byte_data); -#else /* CONFIG_PCI */ - return 0; #endif /* CONFIG_PCI */ } diff -urN linux-2.4.25/drivers/scsi/eata_dma.c linux-2.4.26/drivers/scsi/eata_dma.c --- linux-2.4.25/drivers/scsi/eata_dma.c 2001-09-30 12:26:07.000000000 -0700 +++ linux-2.4.26/drivers/scsi/eata_dma.c 2004-04-14 06:05:31.000000000 -0700 @@ -1067,7 +1067,7 @@ char *buff = 0; unchar bugs = 0; struct Scsi_Host *sh; - hostdata *hd; + hostdata *hd = NULL; int x; diff -urN linux-2.4.25/drivers/scsi/qlogicfc.c linux-2.4.26/drivers/scsi/qlogicfc.c --- linux-2.4.25/drivers/scsi/qlogicfc.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.26/drivers/scsi/qlogicfc.c 2004-04-14 06:05:31.000000000 -0700 @@ -411,7 +411,7 @@ if that mbox should be copied as input. For example 0x2 would mean only copy mbox1. */ -const u_char mbox_param[] = +static const u_char mbox_param[] = { 0x01, /* MBOX_NO_OP */ 0x1f, /* MBOX_LOAD_RAM */ diff -urN linux-2.4.25/drivers/scsi/qlogicpti.c linux-2.4.26/drivers/scsi/qlogicpti.c --- linux-2.4.25/drivers/scsi/qlogicpti.c 2001-10-30 15:08:11.000000000 -0800 +++ linux-2.4.26/drivers/scsi/qlogicpti.c 2004-04-14 06:05:31.000000000 -0700 @@ -53,7 +53,7 @@ #define PACKB(a, b) (((a)<<4)|(b)) -const u_char mbox_param[] = { +static const u_char mbox_param[] = { PACKB(1, 1), /* MBOX_NO_OP */ PACKB(5, 5), /* MBOX_LOAD_RAM */ PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ diff -urN linux-2.4.25/drivers/scsi/scsi_error.c linux-2.4.26/drivers/scsi/scsi_error.c --- linux-2.4.25/drivers/scsi/scsi_error.c 2002-11-28 15:53:14.000000000 -0800 +++ linux-2.4.26/drivers/scsi/scsi_error.c 2004-04-14 06:05:31.000000000 -0700 @@ -110,25 +110,13 @@ int timeout, void (*complete) (Scsi_Cmnd *)) { - - /* - * If the clock was already running for this command, then - * first delete the timer. The timer handling code gets rather - * confused if we don't do this. - */ - if (SCset->eh_timeout.function != NULL) { - del_timer(&SCset->eh_timeout); - } SCset->eh_timeout.data = (unsigned long) SCset; - SCset->eh_timeout.expires = jiffies + timeout; SCset->eh_timeout.function = (void (*)(unsigned long)) complete; + mod_timer(&SCset->eh_timeout, jiffies + timeout); SCset->done_late = 0; SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete)); - - add_timer(&SCset->eh_timeout); - } /* diff -urN linux-2.4.25/drivers/scsi/scsi_lib.c linux-2.4.26/drivers/scsi/scsi_lib.c --- linux-2.4.25/drivers/scsi/scsi_lib.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/scsi/scsi_lib.c 2004-04-14 06:05:31.000000000 -0700 @@ -405,6 +405,14 @@ */ if (req->bh) { /* + * Recount segments whether we are immediately going to + * requeue the command or not, other code might requeue + * it later and since we changed the segment count up above, + * we need it updated. + */ + recount_segments(SCpnt); + + /* * Bleah. Leftovers again. Stick the leftovers in * the front of the queue, and goose the queue again. */ @@ -966,15 +974,6 @@ */ if( req->special != NULL ) { SCpnt = (Scsi_Cmnd *) req->special; - /* - * We need to recount the number of - * scatter-gather segments here - the - * normal case code assumes this to be - * correct, as it would be a performance - * lose to always recount. Handling - * errors is always unusual, of course. - */ - recount_segments(SCpnt); } else { SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE); } diff -urN linux-2.4.25/drivers/scsi/scsi_scan.c linux-2.4.26/drivers/scsi/scsi_scan.c --- linux-2.4.25/drivers/scsi/scsi_scan.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/scsi/scsi_scan.c 2004-04-14 06:05:31.000000000 -0700 @@ -176,6 +176,7 @@ {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, + {"APPLE", "Xserve", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "MSA1000 VOLUME", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "HSV110", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, @@ -189,6 +190,7 @@ {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI XP Arrays */ + {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI 9960 */ {"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN}, {"DotHill","SANnet RAID X300", "*", BLIST_SPARSELUN}, {"SUN", "T300", "*", BLIST_SPARSELUN}, @@ -221,10 +223,14 @@ static unsigned int max_scsi_luns = 1; #endif +static unsigned int scsi_allow_ghost_devices = 0; + #ifdef MODULE MODULE_PARM(max_scsi_luns, "i"); MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); +MODULE_PARM(scsi_allow_ghost_devices, "i"); +MODULE_PARM_DESC(scsi_allow_ghost_devices, "allow devices marked as being offline to be accessed anyway (0 = off, else allow ghosts on lun 0 through scsi_allow_ghost_devices - 1"); #else @@ -244,6 +250,21 @@ __setup("max_scsi_luns=", scsi_luns_setup); +static int __init scsi_allow_ghost_devices_setup(char *str) +{ + unsigned int tmp; + + if (get_option(&str, &tmp) == 1) { + scsi_allow_ghost_devices = tmp; + return 1; + } else { + printk("scsi_allow_ghost_devices_setup: usage scsi_allow_ghost_devices=n (0: off else\nallow ghost devices (ghost devices are devices that report themselves as\nbeing offline but which we allow access to anyway) on lun 0 through n - 1.\n"); + return 0; + } +} + +__setup("scsi_allow_ghost_devices=", scsi_allow_ghost_devices_setup); + #endif static void print_inquiry(unsigned char *data) @@ -620,6 +641,7 @@ } else { /* assume no peripheral if any other sort of error */ scsi_release_request(SRpnt); + scsi_release_commandblocks(SDpnt); return 0; } } @@ -630,6 +652,24 @@ */ /* + * If we are offline and we are on a LUN != 0, then skip this entry. + * If we are on a BLIST_FORCELUN device this will stop the scan at + * the first offline LUN (typically the correct thing to do). If + * we are on a BLIST_SPARSELUN device then this won't stop the scan, + * but it will keep us from having false entries in our device + * array. DL + * + * NOTE: Need to test this to make sure it doesn't cause problems + * with tape autoloaders, multidisc CD changers, and external + * RAID chassis that might use sparse luns or multiluns... DL + */ + if (lun != 0 && (scsi_result[0] >> 5) == 1) { + scsi_release_request(SRpnt); + scsi_release_commandblocks(SDpnt); + return 0; + } + + /* * Get any flags for this device. */ bflags = get_device_flags (scsi_result); @@ -667,8 +707,11 @@ SDpnt->removable = (0x80 & scsi_result[1]) >> 7; /* Use the peripheral qualifier field to determine online/offline */ - if (((scsi_result[0] >> 5) & 7) == 1) SDpnt->online = FALSE; - else SDpnt->online = TRUE; + if ((((scsi_result[0] >> 5) & 7) == 1) && + (lun >= scsi_allow_ghost_devices)) + SDpnt->online = FALSE; + else + SDpnt->online = TRUE; SDpnt->lockable = SDpnt->removable; SDpnt->changed = 0; SDpnt->access_count = 0; @@ -876,11 +919,26 @@ * I think we need REPORT LUNS in future to avoid scanning * of unused LUNs. But, that is another item. */ + /* if (*max_dev_lun < shpnt->max_lun) *max_dev_lun = shpnt->max_lun; else if ((max_scsi_luns >> 1) >= *max_dev_lun) *max_dev_lun += shpnt->max_lun; else *max_dev_lun = max_scsi_luns; + */ + /* + * Blech...the above code is broken. When you have a device + * that is present, and it is a FORCELUN device, then we + * need to scan *all* the luns on that device. Besides, + * skipping the scanning of LUNs is a false optimization. + * Scanning for a LUN on a present device is a very fast + * operation, it's scanning for devices that don't exist that + * is expensive and slow (although if you are truly scanning + * through MAX_SCSI_LUNS devices that would be bad, I hope + * all of the controllers out there set a reasonable value + * in shpnt->max_lun). DL + */ + *max_dev_lun = shpnt->max_lun; return 1; } /* diff -urN linux-2.4.25/drivers/scsi/scsi_syms.c linux-2.4.26/drivers/scsi/scsi_syms.c --- linux-2.4.25/drivers/scsi/scsi_syms.c 2002-08-02 17:39:44.000000000 -0700 +++ linux-2.4.26/drivers/scsi/scsi_syms.c 2004-04-14 06:05:31.000000000 -0700 @@ -43,6 +43,7 @@ EXPORT_SYMBOL(scsi_do_cmd); EXPORT_SYMBOL(scsi_command_size); EXPORT_SYMBOL(scsi_ioctl); +EXPORT_SYMBOL(scsi_finish_command); EXPORT_SYMBOL(print_command); EXPORT_SYMBOL(print_sense); EXPORT_SYMBOL(print_req_sense); diff -urN linux-2.4.25/drivers/scsi/sym53c8xx.c linux-2.4.26/drivers/scsi/sym53c8xx.c --- linux-2.4.25/drivers/scsi/sym53c8xx.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.26/drivers/scsi/sym53c8xx.c 2004-04-14 06:05:32.000000000 -0700 @@ -6992,7 +6992,7 @@ static void ncr_soft_reset(ncb_p np) { - u_char istat; + u_char istat = 0; int i; if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SRUN)) @@ -11981,6 +11981,19 @@ inq_byte7 |= INQ7_SYNC; /* + ** Don't do PPR negotiations on SCSI-2 devices unless + ** they set the DT bit (0x04) in byte 57 of the INQUIRY + ** return data. + */ + if (((inq_data[2] & 0x07) < 3) && (inq_data[4] < 53 || + !(inq_data[56] & 0x04))) { + if (tp->minsync < 10) + tp->minsync = 10; + if (tp->usrsync < 10) + tp->usrsync = 10; + } + + /* ** Prepare negotiation if SIP capabilities have changed. */ tp->inq_done = 1; diff -urN linux-2.4.25/drivers/scsi/sym53c8xx_2/sym_hipd.c linux-2.4.26/drivers/scsi/sym53c8xx_2/sym_hipd.c --- linux-2.4.25/drivers/scsi/sym53c8xx_2/sym_hipd.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/scsi/sym53c8xx_2/sym_hipd.c 2004-04-14 06:05:32.000000000 -0700 @@ -221,7 +221,7 @@ */ static void sym_soft_reset (hcb_p np) { - u_char istat; + u_char istat = 0; int i; if (!(np->features & FE_ISTAT1) || !(INB (nc_istat1) & SCRUN)) diff -urN linux-2.4.25/drivers/sound/i810_audio.c linux-2.4.26/drivers/sound/i810_audio.c --- linux-2.4.25/drivers/sound/i810_audio.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/sound/i810_audio.c 2004-04-14 06:05:32.000000000 -0700 @@ -120,9 +120,15 @@ #ifndef PCI_DEVICE_ID_INTEL_ICH5 #define PCI_DEVICE_ID_INTEL_ICH5 0x24d5 #endif +#ifndef PCI_DEVICE_ID_INTEL_ICH6_3 +#define PCI_DEVICE_ID_INTEL_ICH6_3 0x266e +#endif #ifndef PCI_DEVICE_ID_INTEL_440MX #define PCI_DEVICE_ID_INTEL_440MX 0x7195 #endif +#ifndef PCI_DEVICE_ID_INTEL_ESB_5 +#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 +#endif #ifndef PCI_DEVICE_ID_SI_7012 #define PCI_DEVICE_ID_SI_7012 0x7012 #endif @@ -343,6 +349,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768}, {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AC97, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, + {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, + {0,} }; @@ -2785,7 +2796,8 @@ */ /* see i810_ac97_init for the next 7 lines (jsaw) */ inw(card->ac97base); - if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5) + if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5 || + card->pci_id == PCI_DEVICE_ID_INTEL_ESB_5 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH6_3) && (card->use_mmio)) { primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3; printk(KERN_INFO "i810_audio: Primary codec has ID %d\n", @@ -2855,7 +2867,8 @@ possible IO channels. Bit 0:1 of SDM then holds the last codec ID spoken to. */ - if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5) + if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH5 || + card->pci_id == PCI_DEVICE_ID_INTEL_ESB_5 || card->pci_id == PCI_DEVICE_ID_INTEL_ICH6_3) && (card->use_mmio)) { ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3; printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n", diff -urN linux-2.4.25/drivers/sound/sb_audio.c linux-2.4.26/drivers/sound/sb_audio.c --- linux-2.4.25/drivers/sound/sb_audio.c 2002-02-25 11:38:06.000000000 -0800 +++ linux-2.4.26/drivers/sound/sb_audio.c 2004-04-14 06:05:32.000000000 -0700 @@ -879,7 +879,7 @@ c -= locallen; p += locallen; } /* used = ( samples * 16 bits size ) */ - *used = len << 1; + *used = max_in > ( max_out << 1) ? (max_out << 1) : max_in; /* returned = ( samples * 8 bits size ) */ *returned = len; } diff -urN linux-2.4.25/drivers/usb/audio.c linux-2.4.26/drivers/usb/audio.c --- linux-2.4.25/drivers/usb/audio.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/usb/audio.c 2004-04-14 06:05:32.000000000 -0700 @@ -1684,12 +1684,12 @@ alts->endpoint[1].bmAttributes != 0x01 || alts->endpoint[1].bSynchAddress != 0 || alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in but has invalid synch pipe; treating as asynchronous in\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].bRefresh; } - u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; @@ -1779,12 +1779,12 @@ alts->endpoint[1].bmAttributes != 0x01 || alts->endpoint[1].bSynchAddress != 0 || alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) { - printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n", + printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out but has invalid synch pipe; treating as adaptive out\n", dev->devnum, u->interface, fmt->altsetting); - return -1; + } else { + u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf); + u->syncinterval = alts->endpoint[1].bRefresh; } - u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf); - u->syncinterval = alts->endpoint[1].bRefresh; } if (d->srate < fmt->sratelo) d->srate = fmt->sratelo; diff -urN linux-2.4.25/drivers/usb/gadget/Config.in linux-2.4.26/drivers/usb/gadget/Config.in --- linux-2.4.25/drivers/usb/gadget/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/Config.in 2004-04-14 06:05:32.000000000 -0700 @@ -31,6 +31,9 @@ define_tristate CONFIG_USB_GADGET_CONTROLLER $CONFIG_USB_GOKU fi + # or any other controller that supports high speed transfers ... + define_bool CONFIG_USB_GADGET_DUALSPEED $CONFIG_USB_GADGET_NET2280 + if [ "$CONFIG_USB_GADGET_CONTROLLER" = "y" -o "$CONFIG_USB_GADGET_CONTROLLER" = "m" ] ; then # diff -urN linux-2.4.25/drivers/usb/gadget/Makefile linux-2.4.26/drivers/usb/gadget/Makefile --- linux-2.4.25/drivers/usb/gadget/Makefile 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/Makefile 2004-04-14 06:05:32.000000000 -0700 @@ -16,10 +16,10 @@ controller-$(CONFIG_USB_GOKU) += goku_udc.o # ... and only one of these, too; kbuild/kconfig don't help though. -g_zero-objs := zero.o usbstring.o +g_zero-objs := zero.o usbstring.o config.o obj-$(CONFIG_USB_ZERO) += g_zero.o -g_ether-objs := ether.o usbstring.o +g_ether-objs := ether.o usbstring.o config.o obj-$(CONFIG_USB_ETH) += g_ether.o g_file_storage-objs := file_storage.o usbstring.o diff -urN linux-2.4.25/drivers/usb/gadget/config.c linux-2.4.26/drivers/usb/gadget/config.c --- linux-2.4.25/drivers/usb/gadget/config.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/config.c 2004-04-14 06:05:32.000000000 -0700 @@ -0,0 +1,115 @@ +/* + * usb/gadget/config.c -- simplify building config descriptors + * + * Copyright (C) 2003 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include + + +/** + * usb_descriptor_fillbuf - fill buffer with descriptors + * @buf: Buffer to be filled + * @buflen: Size of buf + * @src: Array of descriptor pointers, terminated by null pointer. + * + * Copies descriptors into the buffer, returning the length or a + * negative error code if they can't all be copied. Useful when + * assembling descriptors for an associated set of interfaces used + * as part of configuring a composite device; or in other cases where + * sets of descriptors need to be marshaled. + */ +int +usb_descriptor_fillbuf(void *buf, unsigned buflen, + const struct usb_descriptor_header **src) +{ + u8 *dest = buf; + + if (!src) + return -EINVAL; + + /* fill buffer from src[] until null descriptor ptr */ + for (; 0 != *src; src++) { + unsigned len = (*src)->bLength; + + if (len > buflen); + return -EINVAL; + memcpy(dest, *src, len); + buflen -= len; + dest += len; + } + return dest - (u8 *)buf; +} + + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} + diff -urN linux-2.4.25/drivers/usb/gadget/ether.c linux-2.4.26/drivers/usb/gadget/ether.c --- linux-2.4.25/drivers/usb/gadget/ether.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/ether.c 2004-04-14 06:05:32.000000000 -0700 @@ -19,7 +19,7 @@ */ -#define DEBUG 1 +// #define DEBUG 1 // #define VERBOSE #include @@ -136,7 +136,6 @@ * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support * WAKEUP ... if hardware supports remote wakeup AND we will issue the * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * @@ -174,7 +173,6 @@ #define EP_IN_NUM 2 static const char EP_STATUS_NAME [] = "ep-f"; #define EP_STATUS_NUM 3 -#define HIGHSPEED /* supports remote wakeup, but this driver doesn't */ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); @@ -323,7 +321,7 @@ #define DEFAULT_QLEN 2 /* double buffering by default */ #endif -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED static unsigned qmult = 5; MODULE_PARM (qmult, "i"); @@ -336,7 +334,7 @@ /* also defer IRQs on highspeed TX */ #define TX_DELAY DEFAULT_QLEN -#else /* !HIGHSPEED ... full speed: */ +#else /* full speed (low speed doesn't do bulk) */ #define qlen(gadget) DEFAULT_QLEN #endif @@ -619,7 +617,26 @@ .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &fs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_sink_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -672,6 +689,25 @@ .bNumConfigurations = 1, }; +static const struct usb_descriptor_header *hs_function [] = { +#ifdef DEV_CONFIG_CDC + /* "cdc" mode descriptors */ + (struct usb_descriptor_header *) &control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) ðer_desc, +#ifdef EP_STATUS_NUM + (struct usb_descriptor_header *) &hs_status_desc, +#endif + (struct usb_descriptor_header *) &data_nop_intf, +#endif /* DEV_CONFIG_CDC */ + /* minimalist core */ + (struct usb_descriptor_header *) &data_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -681,7 +717,7 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ @@ -716,86 +752,25 @@ static int config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { - const unsigned config_len = USB_DT_CONFIG_SIZE -#ifdef DEV_CONFIG_CDC - + 2 * USB_DT_INTERFACE_SIZE - + sizeof header_desc - + sizeof union_desc - + sizeof ether_desc -#ifdef EP_STATUS_NUM - + USB_DT_ENDPOINT_SIZE -#endif -#endif /* DEV_CONFIG_CDC */ - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; + int len; + const struct usb_descriptor_header **function = fs_function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (speed == USB_SPEED_HIGH); -#ifdef HIGHSPEED - int hs; -#endif - /* a single configuration must always be index 0 */ - if (index > 0) - return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; - - /* config (or other speed config) */ - memcpy (buf, ð_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#endif - -#ifdef DEV_CONFIG_CDC - /* control interface, class descriptors, optional status endpoint */ - memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - memcpy (buf, &header_desc, sizeof header_desc); - buf += sizeof header_desc; - memcpy (buf, &union_desc, sizeof union_desc); - buf += sizeof union_desc; - memcpy (buf, ðer_desc, sizeof ether_desc); - buf += sizeof ether_desc; - -#ifdef EP_STATUS_NUM -#ifdef HIGHSPEED if (hs) - memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE); - else -#endif /* HIGHSPEED */ - memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; -#endif /* EP_STATUS_NUM */ - - /* default data altsetting has no endpoints */ - memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#endif /* DEV_CONFIG_CDC */ - - /* the "real" data interface has two endpoints */ - memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; -#ifdef HIGHSPEED - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + function = hs_function; #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - return config_len; + /* a single configuration must always be index 0 */ + if (index > 0) + return -EINVAL; + len = usb_gadget_config_buf (ð_config, buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -897,8 +872,11 @@ #ifndef DEV_CONFIG_CDC if (result == 0) { netif_carrier_on (dev->net); - if (netif_running (dev->net)) + if (netif_running (dev->net)) { + spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); + spin_lock (&dev->lock); + } } else { (void) usb_ep_disable (dev->in_ep); dev->in_ep = 0; @@ -1001,7 +979,7 @@ switch (gadget->speed) { case USB_SPEED_FULL: speed = "full"; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: speed = "high"; break; #endif default: speed = "?"; break; @@ -1172,15 +1150,19 @@ value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, ctrl->wValue >> 8, @@ -1258,8 +1240,11 @@ #ifdef EP_STATUS_NUM issue_start_status (dev); #endif - if (netif_running (dev->net)) + if (netif_running (dev->net)) { + spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); + spin_lock (&dev->lock); + } } else { netif_stop_queue (dev->net); netif_carrier_off (dev->net); @@ -1426,16 +1411,14 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) { struct sk_buff *skb; - int retval = 0; + int retval = -ENOMEM; size_t size; size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); - defer_kevent (dev, WORK_RX_MEMORY); - list_add (&req->list, &dev->rx_reqs); - return -ENOMEM; + goto enomem; } req->buf = skb->data; @@ -1445,11 +1428,14 @@ retval = usb_ep_queue (dev->out_ep, req, gfp_flags); if (retval == -ENOMEM) +enomem: defer_kevent (dev, WORK_RX_MEMORY); if (retval) { DEBUG (dev, "rx submit --> %d\n", retval); dev_kfree_skb_any (skb); + spin_lock (&dev->lock); list_add (&req->list, &dev->rx_reqs); + spin_unlock (&dev->lock); } return retval; } @@ -1514,6 +1500,7 @@ dev_kfree_skb_any (skb); if (!netif_running (dev->net)) { clean: + /* nobody reading rx_reqs, so no dev->lock */ list_add (&req->list, &dev->rx_reqs); req = 0; } @@ -1580,19 +1567,26 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags) { struct usb_request *req; + unsigned long flags; clear_bit (WORK_RX_MEMORY, &dev->todo); /* fill unused rxq slots with some skb */ + spin_lock_irqsave (&dev->lock, flags); while (!list_empty (&dev->rx_reqs)) { req = container_of (dev->rx_reqs.next, struct usb_request, list); list_del_init (&req->list); + spin_unlock_irqrestore (&dev->lock, flags); + if (rx_submit (dev, req, gfp_flags) < 0) { defer_kevent (dev, WORK_RX_MEMORY); return; } + + spin_lock_irqsave (&dev->lock, flags); } + spin_unlock_irqrestore (&dev->lock, flags); } static void eth_work (void *_dev) @@ -1628,7 +1622,9 @@ } dev->stats.tx_packets++; + spin_lock (&dev->lock); list_add (&req->list, &dev->tx_reqs); + spin_unlock (&dev->lock); dev_kfree_skb_any (skb); atomic_dec (&dev->tx_qlen); @@ -1642,11 +1638,14 @@ int length = skb->len; int retval; struct usb_request *req = 0; + unsigned long flags; + spin_lock_irqsave (&dev->lock, flags); req = container_of (dev->tx_reqs.next, struct usb_request, list); list_del (&req->list); if (list_empty (&dev->tx_reqs)) netif_stop_queue (net); + spin_unlock_irqrestore (&dev->lock, flags); /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. @@ -1667,7 +1666,7 @@ #endif req->length = length; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* throttle highspeed IRQ rate back slightly */ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0) @@ -1687,9 +1686,11 @@ if (retval) { dev->stats.tx_dropped++; dev_kfree_skb_any (skb); + spin_lock_irqsave (&dev->lock, flags); if (list_empty (&dev->tx_reqs)) netif_start_queue (net); list_add (&req->list, &dev->tx_reqs); + spin_unlock_irqrestore (&dev->lock, flags); } return 0; } @@ -1788,7 +1789,7 @@ #endif device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; #endif @@ -1810,9 +1811,7 @@ /* network device setup */ dev->net = net; SET_MODULE_OWNER (net); - net->priv = dev; strcpy (net->name, "usb%d"); - ether_setup (net); /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. @@ -1886,7 +1885,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver eth_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff -urN linux-2.4.25/drivers/usb/gadget/gadget_chips.h linux-2.4.26/drivers/usb/gadget/gadget_chips.h --- linux-2.4.25/drivers/usb/gadget/gadget_chips.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/gadget_chips.h 2004-04-14 06:05:32.000000000 -0700 @@ -0,0 +1,57 @@ +/* + * USB device controllers have lots of quirks. Use these macros in + * gadget drivers or other code that needs to deal with them, and which + * autoconfigures instead of using early binding to the hardware. + * + * This could eventually work like the ARM mach_is_*() stuff, driven by + * some config file that gets updated as new hardware is supported. + * + * NOTE: some of these controller drivers may not be available yet. + */ +#ifdef CONFIG_USB_GADGET_NET2280 +#define gadget_is_net2280(g) !strcmp("net2280", (g)->name) +#else +#define gadget_is_net2280(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_PXA +#define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) +#else +#define gadget_is_pxa(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_GOKU +#define gadget_is_goku(g) !strcmp("goku_udc", (g)->name) +#else +#define gadget_is_goku(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SUPERH +#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name) +#else +#define gadget_is_sh(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_SA1100 +#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name) +#else +#define gadget_is_sa1100(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_MQ11XX +#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name) +#else +#define gadget_is_mq11xx(g) 0 +#endif + +#ifdef CONFIG_USB_GADGET_OMAP +#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name) +#else +#define gadget_is_omap(g) 0 +#endif + +// CONFIG_USB_GADGET_AT91RM9200 +// CONFIG_USB_GADGET_SX2 +// CONFIG_USB_GADGET_AU1X00 +// ... + diff -urN linux-2.4.25/drivers/usb/gadget/net2280.c linux-2.4.26/drivers/usb/gadget/net2280.c --- linux-2.4.25/drivers/usb/gadget/net2280.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/net2280.c 2004-04-14 06:05:32.000000000 -0700 @@ -2718,6 +2718,7 @@ spin_lock_init (&dev->lock); dev->pdev = pdev; dev->gadget.ops = &net2280_ops; + dev->gadget.is_dualspeed = 1; dev->gadget.dev.bus_id = pdev->slot_name; dev->gadget.name = driver_name; diff -urN linux-2.4.25/drivers/usb/gadget/usbstring.c linux-2.4.26/drivers/usb/gadget/usbstring.c --- linux-2.4.25/drivers/usb/gadget/usbstring.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/usbstring.c 2004-04-14 06:05:32.000000000 -0700 @@ -16,24 +16,89 @@ #include #include +#include + + +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len) +{ + int count = 0; + u8 c; + u16 uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u8) *s++) != 0) { + if (unlikely(c & 0x80)) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + put_unaligned (cpu_to_le16 (uchar), cp++); + count++; + len--; + } + return count; +fail: + return -1; +} + /** * usb_gadget_get_string - fill out a string descriptor - * @table: of c strings using iso latin/1 characters + * @table: of c strings encoded using UTF-8 * @id: string id, from low byte of wValue in get string descriptor * @buf: at least 256 bytes * - * Finds the iso latin/1 string matching the ID, and converts it into a + * Finds the UTF-8 string matching the ID, and converts it into a * string descriptor in utf16-le. * Returns length of descriptor (always even) or negative errno * - * If your driver needs stings in multiple languages, you'll need to - * to use some alternate solution for languages where the ISO 8859/1 - * (latin/1) character set can't be used. For example, they can't be - * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other - * languages. You'd likely "switch (wIndex) { ... }" in your ep0 - * string descriptor logic, using this routine in cases where "western - * european" characters suffice for the strings being returned. + * If your driver needs stings in multiple languages, you'll probably + * "switch (wIndex) { ... }" in your ep0 string descriptor logic, + * using this routine after choosing which set of UTF-8 strings to use. + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 + * characters (which are also widely used in C strings). */ int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) @@ -59,13 +124,12 @@ /* string descriptors have length, tag, then UTF16-LE text */ len = min ((size_t) 126, strlen (s->s)); + memset (buf + 2, 0, 2 * len); /* zero all the bytes */ + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len); + if (len < 0) + return -EINVAL; buf [0] = (len + 1) * 2; buf [1] = USB_DT_STRING; - memset (buf + 2, 0, 2 * len); /* zero all the high bytes */ - while (len) { - buf [2 * len] = s->s [len - 1]; - len--; - } return buf [0]; } diff -urN linux-2.4.25/drivers/usb/gadget/zero.c linux-2.4.26/drivers/usb/gadget/zero.c --- linux-2.4.25/drivers/usb/gadget/zero.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/gadget/zero.c 2004-04-14 06:05:32.000000000 -0700 @@ -1,7 +1,7 @@ /* * zero.c -- Gadget Zero, for USB development * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -101,6 +101,11 @@ /*-------------------------------------------------------------------------*/ /* + * driver assumes self-powered hardware, and + * has no way for users to trigger remote wakeup. + */ + +/* * hardware-specific configuration, controlled by which device * controller driver was configured. * @@ -108,11 +113,6 @@ * DRIVER_VERSION_NUM ... alerts the host side driver to differences * EP_*_NAME ... which endpoints do we use for which purpose? * EP_*_NUM ... numbers for them (often limited by hardware) - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP * * add other defines for other portability issues, like hardware that * for some reason doesn't handle full speed bulk maxpacket of 64. @@ -136,9 +136,6 @@ #define EP_OUT_NUM 2 static const char EP_IN_NAME [] = "ep-b"; #define EP_IN_NUM 2 -#define HIGHSPEED -/* specific hardware configs could be bus-powered */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -159,8 +156,6 @@ #define EP_OUT_NUM 12 static const char EP_IN_NAME [] = "ep11in-bulk"; #define EP_IN_NUM 11 -/* doesn't support bus-powered operation */ -/* supports remote wakeup, but this driver doesn't */ #endif /* @@ -181,8 +176,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2in-bulk"; #define EP_IN_NUM 2 -/* doesn't support bus-powered operation */ -/* doesn't support remote wakeup? */ #endif /* @@ -197,7 +190,6 @@ #define EP_OUT_NUM 1 static const char EP_IN_NAME [] = "ep2-bulk"; #define EP_IN_NUM 2 -/* doesn't support remote wakeup */ #endif /*-------------------------------------------------------------------------*/ @@ -206,30 +198,6 @@ # error Configure some USB peripheral controller driver! #endif -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif - /*-------------------------------------------------------------------------*/ /* big enough to hold our biggest descriptor */ @@ -284,8 +252,8 @@ /* * Normally the "loopback" configuration is second (index 1) so * it's not the default. Here's where to change that order, to - * work better with hosts (like Linux ... for now!) where config - * changes are problematic. + * work better with hosts where config changes are problematic. + * Or controllers (like superh) that only support one config. */ static int loopdefault = 0; @@ -306,7 +274,7 @@ /* Thanks to NetChip Technologies for donating this product ID. * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ #define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ @@ -358,8 +326,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_SOURCE_SINK, .iConfiguration = STRING_SOURCE_SINK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; static const struct usb_config_descriptor @@ -371,8 +339,8 @@ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_LOOPBACK, .iConfiguration = STRING_LOOPBACK, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, /* self-powered */ }; /* one interface in each configuration */ @@ -419,7 +387,21 @@ .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +static const struct usb_descriptor_header *fs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + 0, +}; + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * usb 2.0 devices need to expose both high speed and full speed @@ -430,22 +412,20 @@ * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), }; @@ -461,6 +441,20 @@ .bNumConfigurations = 2, }; +static const struct usb_descriptor_header *hs_source_sink_function [] = { + (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + +static const struct usb_descriptor_header *hs_loopback_function [] = { + (struct usb_descriptor_header *) &loopback_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, +}; + /* maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) @@ -469,13 +463,14 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +static char manufacturer [40]; static char serial [40]; /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, + { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, longname, }, { STRING_SERIAL, serial, }, { STRING_LOOPBACK, loopback, }, @@ -507,60 +502,42 @@ * device?) */ static int -config_buf (enum usb_device_speed speed, +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { - int is_source_sink; - const unsigned config_len = USB_DT_CONFIG_SIZE - + USB_DT_INTERFACE_SIZE - + 2 * USB_DT_ENDPOINT_SIZE; -#ifdef HIGHSPEED - int hs; + int is_source_sink; + int len; + const struct usb_descriptor_header **function; +#ifdef CONFIG_USB_GADGET_DUALSPEED + int hs = (gadget->speed == USB_SPEED_HIGH); #endif + /* two configurations will always be index 0 and index 1 */ if (index > 1) return -EINVAL; - if (config_len > USB_BUFSIZ) - return -EDOM; is_source_sink = loopdefault ? (index == 1) : (index == 0); - /* config (or other speed config) */ - if (is_source_sink) - memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE); - else - memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE); - buf [1] = type; - ((struct usb_config_descriptor *) buf)->wTotalLength - = __constant_cpu_to_le16 (config_len); - buf += USB_DT_CONFIG_SIZE; - - /* one interface */ - if (is_source_sink) - memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE); - else - memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* the endpoints in that interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; - if (hs) { - memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } else + if (hs) + function = is_source_sink + ? hs_source_sink_function + : hs_loopback_function; + else #endif - { - memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - - return config_len; + function = is_source_sink + ? fs_source_sink_function + : fs_loopback_function; + + len = usb_gadget_config_buf (is_source_sink + ? &source_sink_config + : &loopback_config, + buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; } /*-------------------------------------------------------------------------*/ @@ -1024,17 +1001,21 @@ value = min (ctrl->wLength, (u16) sizeof device_desc); memcpy (req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; value = min (ctrl->wLength, (u16) sizeof dev_qualifier); memcpy (req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; // FALLTHROUGH -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: - value = config_buf (gadget->speed, req->buf, + value = config_buf (gadget, req->buf, ctrl->wValue >> 8, ctrl->wValue & 0xff); if (value >= 0) @@ -1217,14 +1198,26 @@ dev->req->complete = zero_setup_complete; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* assume ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif gadget->ep0->driver_data = dev; INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME); + + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + return 0; enomem: @@ -1235,7 +1228,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver zero_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff -urN linux-2.4.25/drivers/usb/hcd.c linux-2.4.26/drivers/usb/hcd.c --- linux-2.4.25/drivers/usb/hcd.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.26/drivers/usb/hcd.c 2004-04-14 06:05:32.000000000 -0700 @@ -1201,25 +1201,27 @@ return status; // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = pci_map_single ( - hcd->pdev, - urb->setup_packet, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) - urb->transfer_dma = pci_map_single ( - hcd->pdev, - urb->transfer_buffer, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); - - if (urb->dev == hcd->bus->root_hub) + + /* For 2.4, don't map bounce buffer if it's a root hub operation. */ + if (urb->dev == hcd->bus->root_hub) { status = rh_urb_enqueue (hcd, urb); - else + } else { + if (usb_pipecontrol (urb->pipe)) + urb->setup_dma = pci_map_single ( + hcd->pdev, + urb->setup_packet, + sizeof (struct usb_ctrlrequest), + PCI_DMA_TODEVICE); + if (urb->transfer_buffer_length != 0) + urb->transfer_dma = pci_map_single ( + hcd->pdev, + urb->transfer_buffer, + urb->transfer_buffer_length, + usb_pipein (urb->pipe) + ? PCI_DMA_FROMDEVICE + : PCI_DMA_TODEVICE); status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); + } return status; } @@ -1471,6 +1473,11 @@ */ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { + int is_root_hub_operation; + + /* Work this out here as urb_unlink clears urb->dev */ + is_root_hub_operation = (urb->dev == hcd->bus->root_hub); + urb_unlink (urb); // NOTE: a generic device/urb monitoring hook would go here. @@ -1480,11 +1487,14 @@ // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag - if (usb_pipecontrol (urb->pipe)) + + /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */ + if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation) pci_unmap_single (hcd->pdev, urb->setup_dma, sizeof (struct usb_ctrlrequest), PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) + + if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation) pci_unmap_single (hcd->pdev, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) diff -urN linux-2.4.25/drivers/usb/hid-core.c linux-2.4.26/drivers/usb/hid-core.c --- linux-2.4.25/drivers/usb/hid-core.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/hid-core.c 2004-04-14 06:05:32.000000000 -0700 @@ -243,6 +243,9 @@ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + if (usages < parser->global.report_count) + usages = parser->global.report_count; + if (usages == 0) return 0; /* ignore padding fields */ @@ -254,9 +257,13 @@ field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); for (i = 0; i < usages; i++) { - field->usage[i].hid = parser->local.usage[i]; + int j = i; + /* Duplicate the last usage we parsed if we have excess values */ + if (i >= parser->local.usage_index) + j = parser->local.usage_index - 1; + field->usage[i].hid = parser->local.usage[j]; field->usage[i].collection_index = - parser->local.collection_index[i]; + parser->local.collection_index[j]; } field->maxusage = usages; @@ -1182,7 +1189,10 @@ #define USB_VENDOR_ID_MGE 0x0463 #define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS1 0x0001 - + +#define USB_VENDOR_ID_NEC 0x073e +#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 + struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1237,6 +1247,7 @@ { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD }, { 0, 0 } }; diff -urN linux-2.4.25/drivers/usb/hid-input.c linux-2.4.26/drivers/usb/hid-input.c --- linux-2.4.25/drivers/usb/hid-input.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/usb/hid-input.c 2004-04-14 06:05:32.000000000 -0700 @@ -444,8 +444,10 @@ while (list != &report_enum->report_list) { report = (struct hid_report *) list; - if (!report->maxfield) + if (!report->maxfield) { + list = list->next; continue; + } if (!hidinput) { hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); diff -urN linux-2.4.25/drivers/usb/hiddev.c linux-2.4.26/drivers/usb/hiddev.c --- linux-2.4.25/drivers/usb/hiddev.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/usb/hiddev.c 2004-04-14 06:05:32.000000000 -0700 @@ -396,7 +396,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref uref; + struct hiddev_usage_ref_multi uref_multi; + struct hiddev_usage_ref *uref = &uref_multi.uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -554,64 +555,93 @@ return copy_to_user((void *) arg, &finfo, sizeof(finfo)); case HIDIOCGUCODE: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) return -EFAULT; - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; - uref.usage_code = field->usage[uref.usage_index].hid; + uref->usage_code = field->usage[uref->usage_index].hid; - return copy_to_user((void *) arg, &uref, sizeof(uref)); + return copy_to_user((void *) arg, uref, sizeof(*uref)); case HIDIOCGUSAGE: case HIDIOCSUSAGE: + case HIDIOCGUSAGES: + case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: - if (copy_from_user(&uref, (void *) arg, sizeof(uref))) - return -EFAULT; + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (copy_from_user(&uref_multi, (void *) arg, + sizeof(uref_multi))) + return -EFAULT; + } else { + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) + return -EFAULT; + } - if (cmd == HIDIOCSUSAGE && - uref.report_type == HID_REPORT_TYPE_INPUT) + if (cmd != HIDIOCGUSAGE && + cmd != HIDIOCGUSAGES && + uref->report_type == HID_REPORT_TYPE_INPUT) return -EINVAL; - if (uref.report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, &uref); + if (uref->report_id == HID_REPORT_ID_UNKNOWN) { + field = hiddev_lookup_usage(hid, uref); if (field == NULL) return -EINVAL; } else { - rinfo.report_type = uref.report_type; - rinfo.report_id = uref.report_id; + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - if (uref.field_index >= report->maxfield) + if (uref->field_index >= report->maxfield) return -EINVAL; - field = report->field[uref.field_index]; - if (uref.usage_index >= field->maxusage) + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) return -EINVAL; + + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (uref_multi.num_values >= HID_MAX_USAGES || + uref->usage_index >= field->maxusage || + (uref->usage_index + uref_multi.num_values) >= field->maxusage) + return -EINVAL; + } } switch (cmd) { case HIDIOCGUSAGE: - uref.value = field->value[uref.usage_index]; - return copy_to_user((void *) arg, &uref, sizeof(uref)); + uref->value = field->value[uref->usage_index]; + return copy_to_user((void *) arg, uref, sizeof(*uref)); case HIDIOCSUSAGE: - field->value[uref.usage_index] = uref.value; + field->value[uref->usage_index] = uref->value; return 0; case HIDIOCGCOLLECTIONINDEX: - return field->usage[uref.usage_index].collection_index; + return field->usage[uref->usage_index].collection_index; + case HIDIOCGUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + uref_multi.values[i] = + field->value[uref->usage_index + i]; + if (copy_to_user((void *) arg, &uref_multi, + sizeof(uref_multi))) + return -EFAULT; + return 0; + case HIDIOCSUSAGES: + for (i = 0; i < uref_multi.num_values; i++) + field->value[uref->usage_index + i] = + uref_multi.values[i]; + return 0; } break; diff -urN linux-2.4.25/drivers/usb/host/ehci-dbg.c linux-2.4.26/drivers/usb/host/ehci-dbg.c --- linux-2.4.25/drivers/usb/host/ehci-dbg.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/host/ehci-dbg.c 2004-04-14 06:05:32.000000000 -0700 @@ -377,7 +377,7 @@ scratch, cpu_to_le32p (&qh->hw_info2), cpu_to_le32p (&qh->hw_token), mark, (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) - ? "data0" : "data1", + ? "data1" : "data0", (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; next += temp; diff -urN linux-2.4.25/drivers/usb/host/ehci-hub.c linux-2.4.26/drivers/usb/host/ehci-hub.c --- linux-2.4.25/drivers/usb/host/ehci-hub.c 2003-06-13 07:51:36.000000000 -0700 +++ linux-2.4.26/drivers/usb/host/ehci-hub.c 2004-04-14 06:05:33.000000000 -0700 @@ -113,7 +113,7 @@ u16 temp; desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = 0; /* FIXME: f(system power) */ + desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */ desc->bHubContrCurrent = 0; desc->bNbrPorts = ports; diff -urN linux-2.4.25/drivers/usb/host/ehci-sched.c linux-2.4.26/drivers/usb/host/ehci-sched.c --- linux-2.4.25/drivers/usb/host/ehci-sched.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/host/ehci-sched.c 2004-04-14 06:05:33.000000000 -0700 @@ -490,33 +490,6 @@ return status; } -static unsigned -intr_complete ( - struct ehci_hcd *ehci, - unsigned frame, - struct ehci_qh *qh, - struct pt_regs *regs -) { - unsigned count; - - /* nothing to report? */ - if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE)) - != 0)) - return 0; - if (unlikely (list_empty (&qh->qtd_list))) { - dbg ("intr qh %p no TDs?", qh); - return 0; - } - - /* handle any completions */ - count = qh_completions (ehci, qh, regs); - - if (unlikely (list_empty (&qh->qtd_list))) - intr_deschedule (ehci, qh, 0); - - return count; -} - /*-------------------------------------------------------------------------*/ static inline struct ehci_iso_stream * @@ -718,7 +691,8 @@ trans = EHCI_ISOC_ACTIVE; trans |= buf & 0x0fff; - if (unlikely ((i + 1) == urb->number_of_packets)) + if (unlikely (((i + 1) == urb->number_of_packets)) + && !(urb->transfer_flags & URB_NO_INTERRUPT)) trans |= EHCI_ITD_IOC; trans |= length << 16; uframe->transaction = cpu_to_le32 (trans); @@ -809,7 +783,10 @@ * periodic schedule slots. (Affected by TUNE_FLS, which defaults to * "as small as possible" to be cache-friendlier.) That limits the size * transfers you can stream reliably; avoid more than 64 msec per urb. - * Also avoid queue depths of less than the system's worst irq latency. + * Also avoid queue depths of less than ehci's worst irq latency (affected + * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, + * and other factors); or more than about 230 msec total (for portability, + * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! */ #define SCHEDULE_SLOP 10 /* frames */ @@ -1236,7 +1213,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) { unsigned frame, clock, now_uframe, mod; - unsigned count = 0; + unsigned modified; mod = ehci->periodic_size << 3; @@ -1247,47 +1224,50 @@ */ now_uframe = ehci->next_uframe; if (HCD_IS_RUNNING (ehci->hcd.state)) - clock = readl (&ehci->regs->frame_index) % mod; + clock = readl (&ehci->regs->frame_index); else clock = now_uframe + mod - 1; + clock %= mod; for (;;) { union ehci_shadow q, *q_p; u32 type, *hw_p; unsigned uframes; + /* don't scan past the live uframe */ frame = now_uframe >> 3; -restart: - /* scan schedule to _before_ current frame index */ - if ((frame == (clock >> 3)) - && HCD_IS_RUNNING (ehci->hcd.state)) + if (frame == (clock >> 3)) uframes = now_uframe & 0x07; - else + else { + /* safe to scan the whole frame at once */ + now_uframe |= 0x07; uframes = 8; + } +restart: + /* scan each element in frame's queue for completions */ q_p = &ehci->pshadow [frame]; hw_p = &ehci->periodic [frame]; q.ptr = q_p->ptr; type = Q_NEXT_TYPE (*hw_p); + modified = 0; - /* scan each element in frame's queue for completions */ while (q.ptr != 0) { - int last; unsigned uf; union ehci_shadow temp; switch (type) { case Q_TYPE_QH: - last = (q.qh->hw_next == EHCI_LIST_END); - temp = q.qh->qh_next; + /* handle any completions */ + temp.qh = qh_get (q.qh); type = Q_NEXT_TYPE (q.qh->hw_next); - count += intr_complete (ehci, frame, - qh_get (q.qh), regs); - qh_put (ehci, q.qh); - q = temp; + q = q.qh->qh_next; + modified = qh_completions (ehci, temp.qh, regs); + if (unlikely (list_empty (&temp.qh->qtd_list))) + intr_deschedule (ehci, temp.qh, 0); + qh_put (ehci, temp.qh); break; case Q_TYPE_FSTN: - last = (q.fstn->hw_next == EHCI_LIST_END); /* for "save place" FSTNs, look at QH entries * in the previous frame for completions. */ @@ -1298,8 +1278,6 @@ q = q.fstn->fstn_next; break; case Q_TYPE_ITD: - last = (q.itd->hw_next == EHCI_LIST_END); - /* skip itds for later in the frame */ rmb (); for (uf = uframes; uf < 8; uf++) { @@ -1320,31 +1298,24 @@ */ *q_p = q.itd->itd_next; *hw_p = q.itd->hw_next; + type = Q_NEXT_TYPE (q.itd->hw_next); wmb(); - - /* always rescan here; simpler */ - count += itd_complete (ehci, q.itd, regs); - goto restart; + modified = itd_complete (ehci, q.itd, regs); + q = *q_p; + break; #ifdef have_split_iso case Q_TYPE_SITD: - last = (q.sitd->hw_next == EHCI_LIST_END); - sitd_complete (ehci, q.sitd); - type = Q_NEXT_TYPE (q.sitd->hw_next); - - // FIXME unlink SITD after split completes - q = q.sitd->sitd_next; - break; + // nyet! #endif /* have_split_iso */ default: dbg ("corrupt type %d frame %d shadow %p", type, frame, q.ptr); // BUG (); - last = 1; q.ptr = 0; } - /* did completion remove an interior q entry? */ - if (unlikely (q.ptr == 0 && !last)) + /* assume completion callbacks modify the queue */ + if (unlikely (modified)) goto restart; } @@ -1371,9 +1342,6 @@ /* rescan the rest of this frame, then ... */ clock = now; } else { - /* FIXME sometimes we can scan the next frame - * right away, not always inching up on it ... - */ now_uframe++; now_uframe %= mod; } diff -urN linux-2.4.25/drivers/usb/host/usb-ohci.c linux-2.4.26/drivers/usb/host/usb-ohci.c --- linux-2.4.25/drivers/usb/host/usb-ohci.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/host/usb-ohci.c 2004-04-14 06:05:33.000000000 -0700 @@ -104,10 +104,6 @@ #define OHCI_UNLINK_TIMEOUT (HZ / 10) -static LIST_HEAD (ohci_hcd_list); -static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; - - /*-------------------------------------------------------------------------*/ /* AMD-756 (D2 rev) reports corrupt register contents in some cases. @@ -134,6 +130,57 @@ /*-------------------------------------------------------------------------* * URB support functions *-------------------------------------------------------------------------*/ + +static void ohci_complete_add(struct ohci *ohci, struct urb *urb) +{ + + if (urb->hcpriv != NULL) { + printk("completing with non-null priv!\n"); + return; + } + + if (ohci->complete_tail == NULL) { + ohci->complete_head = urb; + ohci->complete_tail = urb; + } else { + ohci->complete_head->hcpriv = urb; + ohci->complete_tail = urb; + } +} + +static inline struct urb *ohci_complete_get(struct ohci *ohci) +{ + struct urb *urb; + + if ((urb = ohci->complete_head) == NULL) + return NULL; + if (urb == ohci->complete_tail) { + ohci->complete_tail = NULL; + ohci->complete_head = NULL; + } else { + ohci->complete_head = urb->hcpriv; + } + urb->hcpriv = NULL; + return urb; +} + +static inline void ohci_complete(struct ohci *ohci) +{ + struct urb *urb; + + spin_lock(&ohci->ohci_lock); + while ((urb = ohci_complete_get(ohci)) != NULL) { + spin_unlock(&ohci->ohci_lock); + if (urb->dev) { + usb_dec_dev_use (urb->dev); + urb->dev = NULL; + } + if (urb->complete) + (*urb->complete)(urb); + spin_lock(&ohci->ohci_lock); + } + spin_unlock(&ohci->ohci_lock); +} /* free HCD-private data associated with this URB */ @@ -209,20 +256,14 @@ } urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv); - usb_dec_dev_use (urb->dev); - urb->dev = NULL; + } else { + if (urb->dev != NULL) { + err ("Non-null dev at rm_priv time"); + // urb->dev = NULL; + } } } -static void urb_rm_priv (struct urb * urb) -{ - unsigned long flags; - - spin_lock_irqsave (&usb_ed_lock, flags); - urb_rm_priv_locked (urb); - spin_unlock_irqrestore (&usb_ed_lock, flags); -} - /*-------------------------------------------------------------------------*/ #ifdef DEBUG @@ -466,7 +507,6 @@ { urb_priv_t * urb_priv = urb->hcpriv; struct urb * urbt; - unsigned long flags; int i; if (!urb_priv) @@ -474,7 +514,8 @@ /* just to be sure */ if (!urb->complete) { - urb_rm_priv (urb); + urb_rm_priv_locked (urb); + ohci_complete_add(hc, urb); /* Just usb_dec_dev_use */ return -1; } @@ -490,20 +531,18 @@ usb_pipeout (urb->pipe) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (urb->interval) { urb->complete (urb); - + /* implicitly requeued */ urb->actual_length = 0; urb->status = -EINPROGRESS; td_submit_urb (urb); } else { - urb_rm_priv(urb); - urb->complete (urb); + urb_rm_priv_locked (urb); + ohci_complete_add(hc, urb); } - break; - + break; case PIPE_ISOCHRONOUS: for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next); @@ -515,7 +554,6 @@ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); urb->complete (urb); - spin_lock_irqsave (&usb_ed_lock, flags); urb->actual_length = 0; urb->status = USB_ST_URB_PENDING; urb->start_frame = urb_priv->ed->last_iso + 1; @@ -526,18 +564,17 @@ } td_submit_urb (urb); } - spin_unlock_irqrestore (&usb_ed_lock, flags); - + } else { /* unlink URB, call complete */ - urb_rm_priv (urb); - urb->complete (urb); + urb_rm_priv_locked (urb); + ohci_complete_add(hc, urb); } break; case PIPE_BULK: case PIPE_CONTROL: /* unlink URB, call complete */ - urb_rm_priv (urb); - urb->complete (urb); + urb_rm_priv_locked (urb); + ohci_complete_add(hc, urb); break; } return 0; @@ -574,20 +611,24 @@ #ifdef DEBUG urb_print (urb, "SUB", usb_pipein (pipe)); #endif - + /* handle a request to the virtual root hub */ if (usb_pipedevice (pipe) == ohci->rh.devnum) return rh_submit_urb (urb); - + + spin_lock_irqsave(&ohci->ohci_lock, flags); + /* when controller's hung, permit only roothub cleanup attempts * such as powering down ports */ if (ohci->disabled) { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -ESHUTDOWN; } /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -ENOMEM; } @@ -609,6 +650,7 @@ case PIPE_ISOCHRONOUS: /* number of packets from URB */ size = urb->number_of_packets; if (size <= 0) { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -EINVAL; } @@ -628,8 +670,9 @@ /* allocate the private part of the URB */ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), - in_interrupt() ? GFP_ATOMIC : GFP_NOIO); + GFP_ATOMIC); if (!urb_priv) { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -ENOMEM; } @@ -640,13 +683,12 @@ urb_priv->ed = ed; /* allocate the TDs (updating hash chains) */ - spin_lock_irqsave (&usb_ed_lock, flags); for (i = 0; i < size; i++) { urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC); if (!urb_priv->td[i]) { urb_priv->length = i; urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -ENOMEM; } @@ -654,7 +696,7 @@ if (ed->state == ED_NEW || (ed->state & ED_DEL)) { urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return -EINVAL; } @@ -676,7 +718,7 @@ } if (bustime < 0) { urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (urb->dev); return bustime; } @@ -719,7 +761,7 @@ } #endif - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); return 0; } @@ -750,6 +792,7 @@ if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) return rh_unlink_urb (urb); + spin_lock_irqsave(&ohci->ohci_lock, flags); if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { if (!ohci->disabled) { urb_priv_t * urb_priv; @@ -759,6 +802,7 @@ */ if (!(urb->transfer_flags & USB_ASYNC_UNLINK) && in_interrupt ()) { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); err ("bug in call from %p; use async!", __builtin_return_address(0)); return -EWOULDBLOCK; @@ -767,11 +811,10 @@ /* flag the urb and its TDs for deletion in some * upcoming SF interrupt delete list processing */ - spin_lock_irqsave (&usb_ed_lock, flags); urb_priv = urb->hcpriv; if (!urb_priv || (urb_priv->state == URB_DEL)) { - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); return 0; } @@ -786,7 +829,7 @@ add_wait_queue (&unlink_wakeup, &wait); urb_priv->wait = &unlink_wakeup; - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); /* wait until all TDs are deleted */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -800,14 +843,22 @@ err ("unlink URB timeout"); return -ETIMEDOUT; } + + usb_dec_dev_use (urb->dev); + urb->dev = NULL; + if (urb->complete) + urb->complete (urb); } else { /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); return -EINPROGRESS; } } else { - urb_rm_priv (urb); + urb_rm_priv_locked (urb); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); + usb_dec_dev_use (urb->dev); + urb->dev = NULL; if (urb->transfer_flags & USB_ASYNC_UNLINK) { urb->status = -ECONNRESET; if (urb->complete) @@ -815,6 +866,8 @@ } else urb->status = -ENOENT; } + } else { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); } return 0; } @@ -857,7 +910,7 @@ * (freeing all the TDs, unlinking EDs) but we need * to defend against bugs that prevent that. */ - spin_lock_irqsave (&usb_ed_lock, flags); + spin_lock_irqsave(&ohci->ohci_lock, flags); for(i = 0; i < NUM_EDS; i++) { ed = &(dev->ed[i]); if (ed->state != ED_NEW) { @@ -872,7 +925,7 @@ cnt++; } } - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore(&ohci->ohci_lock, flags); /* if the controller is running, tds for those unlinked * urbs get freed by dl_del_list at the next SF interrupt @@ -1206,17 +1259,12 @@ td_t * td; ed_t * ed_ret; volatile ed_t * ed; - unsigned long flags; - - - spin_lock_irqsave (&usb_ed_lock, flags); ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]); if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { /* pending delete request */ - spin_unlock_irqrestore (&usb_ed_lock, flags); return NULL; } @@ -1229,7 +1277,6 @@ /* out of memory */ if (td) td_free(ohci, td); - spin_unlock_irqrestore (&usb_ed_lock, flags); return NULL; } ed->hwTailP = cpu_to_le32 (td->td_dma); @@ -1252,8 +1299,7 @@ ed->int_period = interval; ed->int_load = load; } - - spin_unlock_irqrestore (&usb_ed_lock, flags); + return ed_ret; } @@ -1512,7 +1558,7 @@ /* handle an urb that is being unlinked */ -static void dl_del_urb (struct urb * urb) +static void dl_del_urb (ohci_t *ohci, struct urb * urb) { wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait; @@ -1520,12 +1566,9 @@ if (urb->transfer_flags & USB_ASYNC_UNLINK) { urb->status = -ECONNRESET; - if (urb->complete) - urb->complete (urb); + ohci_complete_add(ohci, urb); } else { urb->status = -ENOENT; - if (urb->complete) - urb->complete (urb); /* unblock sohci_unlink_urb */ if (wait_head) @@ -1544,10 +1587,7 @@ td_t * td_rev = NULL; td_t * td_list = NULL; urb_priv_t * urb_priv = NULL; - unsigned long flags; - - spin_lock_irqsave (&usb_ed_lock, flags); - + td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; ohci->hcca->done_head = 0; @@ -1573,7 +1613,6 @@ td_rev = td_list; td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0; } - spin_unlock_irqrestore (&usb_ed_lock, flags); return td_list; } @@ -1585,7 +1624,6 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) { - unsigned long flags; ed_t * ed; __u32 edINFO; __u32 tdINFO; @@ -1593,8 +1631,6 @@ __u32 * td_p; int ctrl = 0, bulk = 0; - spin_lock_irqsave (&usb_ed_lock, flags); - for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) { tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0); @@ -1615,7 +1651,7 @@ /* URB is done; clean up */ if (++(urb_priv->td_cnt) == urb_priv->length) - dl_del_urb (urb); + dl_del_urb (ohci, urb); } else { td_p = &td->hwNextTD; } @@ -1672,7 +1708,6 @@ } ohci->ed_rm_list[frame] = NULL; - spin_unlock_irqrestore (&usb_ed_lock, flags); } @@ -1689,9 +1724,7 @@ struct urb * urb; urb_priv_t * urb_priv; __u32 tdINFO, edHeadP, edTailP; - - unsigned long flags; - + while (td_list) { td_list_next = td_list->next_dl_td; @@ -1720,13 +1753,10 @@ urb->status = cc_to_error[cc]; sohci_return_urb (ohci, urb); } else { - spin_lock_irqsave (&usb_ed_lock, flags); - dl_del_urb (urb); - spin_unlock_irqrestore (&usb_ed_lock, flags); + dl_del_urb (ohci, urb); } } - spin_lock_irqsave (&usb_ed_lock, flags); if (ed->state != ED_NEW) { edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0; edTailP = le32_to_cpup (&ed->hwTailP); @@ -1735,7 +1765,6 @@ if ((edHeadP == edTailP) && (ed->state == ED_OPER)) ep_unlink (ohci, ed); } - spin_unlock_irqrestore (&usb_ed_lock, flags); td_list = td_list_next; } @@ -1926,7 +1955,8 @@ int leni = urb->transfer_buffer_length; int len = 0; int status = TD_CC_NOERROR; - + unsigned long flags; + __u32 datab[4]; __u8 * data_buf = (__u8 *) datab; @@ -1935,13 +1965,16 @@ __u16 wIndex; __u16 wLength; + spin_lock_irqsave(&ohci->ohci_lock, flags); + if (usb_pipeint(pipe)) { ohci->rh.urb = urb; ohci->rh.send = 1; ohci->rh.interval = urb->interval; rh_init_int_timer(urb); urb->status = cc_to_error [TD_CC_NOERROR]; - + + spin_unlock_irqrestore(&ohci->ohci_lock, flags); return 0; } @@ -2113,6 +2146,7 @@ #endif urb->hcpriv = NULL; + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use (usb_dev); urb->dev = NULL; if (urb->complete) @@ -2125,13 +2159,16 @@ static int rh_unlink_urb (struct urb * urb) { ohci_t * ohci = urb->dev->bus->hcpriv; + unsigned int flags; + spin_lock_irqsave(&ohci->ohci_lock, flags); if (ohci->rh.urb == urb) { ohci->rh.send = 0; del_timer (&ohci->rh.rh_int_timer); ohci->rh.urb = NULL; urb->hcpriv = NULL; + spin_unlock_irqrestore(&ohci->ohci_lock, flags); usb_dec_dev_use(urb->dev); urb->dev = NULL; if (urb->transfer_flags & USB_ASYNC_UNLINK) { @@ -2140,6 +2177,8 @@ urb->complete (urb); } else urb->status = -ENOENT; + } else { + spin_unlock_irqrestore(&ohci->ohci_lock, flags); } return 0; } @@ -2283,7 +2322,7 @@ static void check_timeouts (struct ohci *ohci) { - spin_lock (&usb_ed_lock); + spin_lock (&ohci->ohci_lock); while (!list_empty (&ohci->timeout_list)) { struct urb *urb; @@ -2296,15 +2335,15 @@ continue; urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK; - spin_unlock (&usb_ed_lock); + spin_unlock (&ohci->ohci_lock); // outside the interrupt handler (in a timer...) // this reference would race interrupts sohci_unlink_urb (urb); - spin_lock (&usb_ed_lock); + spin_lock (&ohci->ohci_lock); } - spin_unlock (&usb_ed_lock); + spin_unlock (&ohci->ohci_lock); } @@ -2318,6 +2357,8 @@ struct ohci_regs * regs = ohci->regs; int ints; + spin_lock (&ohci->ohci_lock); + /* avoid (slow) readl if only WDH happened */ if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { @@ -2326,11 +2367,13 @@ /* cardbus/... hardware gone before remove() */ } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { ohci->disabled++; + spin_unlock (&ohci->ohci_lock); err ("%s device removed!", ohci->ohci_dev->slot_name); return; /* interrupt for some other device? */ } else if ((ints &= readl (®s->intrenable)) == 0) { + spin_unlock (&ohci->ohci_lock); return; } @@ -2381,6 +2424,13 @@ } } + /* + * Finally, we are done with trashing about our hardware lists + * and other CPUs are allowed in. The festive flipping of the lock + * ensues as we struggle with the check_timeouts disaster. + */ + spin_unlock (&ohci->ohci_lock); + if (!list_empty (&ohci->timeout_list)) { check_timeouts (ohci); // FIXME: enable SF as needed in a timer; @@ -2393,6 +2443,8 @@ writel (ints, ®s->intrstatus); writel (OHCI_INTR_MIE, ®s->intrenable); (void)readl (®s->intrdisable); /* PCI posting flush */ + + ohci_complete(ohci); } /*-------------------------------------------------------------------------*/ @@ -2425,10 +2477,8 @@ ohci->ohci_dev = dev; pci_set_drvdata(dev, ohci); - INIT_LIST_HEAD (&ohci->ohci_hcd_list); - list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); - INIT_LIST_HEAD (&ohci->timeout_list); + spin_lock_init(&ohci->ohci_lock); ohci->bus = usb_alloc_bus (&sohci_device_operations); if (!ohci->bus) { @@ -2472,9 +2522,6 @@ usb_free_bus (ohci->bus); } - list_del (&ohci->ohci_hcd_list); - INIT_LIST_HEAD (&ohci->ohci_hcd_list); - ohci_mem_cleanup (ohci); /* unmap the IO address space */ @@ -2720,12 +2767,12 @@ ohci->sleeping = 1; /* First stop processing */ - spin_lock_irqsave (&usb_ed_lock, flags); + spin_lock_irqsave (&ohci->ohci_lock, flags); ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); writel (ohci->hc_control, &ohci->regs->control); writel (OHCI_INTR_SF, &ohci->regs->intrstatus); (void) readl (&ohci->regs->intrstatus); - spin_unlock_irqrestore (&usb_ed_lock, flags); + spin_unlock_irqrestore (&ohci->ohci_lock, flags); /* Wait a frame or two */ mdelay(1); @@ -2851,7 +2898,7 @@ mdelay (3); /* Then re-enable operations */ - spin_lock_irqsave (&usb_ed_lock, flags); + spin_lock_irqsave (&ohci->ohci_lock, flags); ohci->disabled = 0; ohci->sleeping = 0; ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; @@ -2867,7 +2914,6 @@ /* Check for a pending done list */ writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); (void) readl (&ohci->regs->intrdisable); - spin_unlock_irqrestore (&usb_ed_lock, flags); #ifdef CONFIG_PMAC_PBOOK if (_machine == _MACH_Pmac) enable_irq (ohci->irq); @@ -2877,6 +2923,7 @@ writel (OHCI_INTR_WDH, &ohci->regs->intrenable); writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ + spin_unlock_irqrestore (&ohci->ohci_lock, flags); break; default: diff -urN linux-2.4.25/drivers/usb/host/usb-ohci.h linux-2.4.26/drivers/usb/host/usb-ohci.h --- linux-2.4.25/drivers/usb/host/usb-ohci.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/host/usb-ohci.h 2004-04-14 06:05:33.000000000 -0700 @@ -384,12 +384,12 @@ #define OHCI_QUIRK_SUCKYIO 0x02 /* NSC superio */ struct ohci_regs * regs; /* OHCI controller's memory */ - struct list_head ohci_hcd_list; /* list of all ohci_hcd */ struct list_head timeout_list; // struct list_head urb_list; // list of all pending urbs - // spinlock_t urb_list_lock; // lock to keep consistency - + spinlock_t ohci_lock; /* Covers all fields up & down */ + struct urb *complete_head, *complete_tail; + int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */ ed_t * ed_bulktail; /* last endpoint of bulk list */ diff -urN linux-2.4.25/drivers/usb/pegasus.h linux-2.4.26/drivers/usb/pegasus.h --- linux-2.4.25/drivers/usb/pegasus.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/pegasus.h 2004-04-14 06:05:33.000000000 -0700 @@ -126,6 +126,7 @@ #define VENDOR_DLINK 0x2001 #define VENDOR_ELCON 0x0db7 #define VENDOR_ELSA 0x05cc +#define VENDOR_GIGABYTE 0x1044 #define VENDOR_HAWKING 0x0e66 #define VENDOR_HP 0x03f0 #define VENDOR_IODATA 0x04bb @@ -221,6 +222,8 @@ DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, DEFAULT_GPIO_RESET ) +PEGASUS_DEV( "GIGABYTE GN-BR402W Wireless Router", VENDOR_GIGABYTE, 0x8002, + DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c, @@ -263,6 +266,8 @@ DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "OCT Inc.", VENDOR_OCT, 0x0109, DEFAULT_GPIO_RESET | PEGASUS_II ) +PEGASUS_DEV( "OCT USB TO Ethernet", VENDOR_OCT, 0x0901, + DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200, diff -urN linux-2.4.25/drivers/usb/printer.c linux-2.4.26/drivers/usb/printer.c --- linux-2.4.25/drivers/usb/printer.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/printer.c 2004-04-14 06:05:33.000000000 -0700 @@ -604,14 +604,16 @@ { DECLARE_WAITQUEUE(wait, current); struct usblp *usblp = file->private_data; - int timeout, err = 0; + int timeout, err = 0, transfer_length = 0; size_t writecount = 0; while (writecount < count) { if (!usblp->wcomplete) { barrier(); - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + writecount += transfer_length; + return writecount ? writecount : -EAGAIN; + } timeout = USBLP_WRITE_TIMEOUT; add_wait_queue(&usblp->wait, &wait); @@ -655,27 +657,36 @@ continue; } - writecount += usblp->writeurb->transfer_buffer_length; - usblp->writeurb->transfer_buffer_length = 0; - + /* We must increment writecount here, and not at the + * end of the loop. Otherwise, the final loop iteration may + * be skipped, leading to incomplete printer output. + */ + writecount += transfer_length; if (writecount == count) { up (&usblp->sem); break; } - usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ? - (count - writecount) : USBLP_BUF_SIZE; + transfer_length = count - writecount; + if(transfer_length > USBLP_BUF_SIZE) + transfer_length = USBLP_BUF_SIZE; + + usblp->writeurb->transfer_buffer_length = transfer_length; - if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount, - usblp->writeurb->transfer_buffer_length)) { + if (copy_from_user(usblp->writeurb->transfer_buffer, + buffer + writecount, transfer_length)) { up(&usblp->sem); return writecount ? writecount : -EFAULT; } usblp->writeurb->dev = usblp->dev; usblp->wcomplete = 0; - if (usb_submit_urb(usblp->writeurb)) { - count = -EIO; + err = usb_submit_urb(usblp->writeurb); + if (err) { + if (err != -ENOMEM) + count = -EIO; + else + count = writecount ? writecount : -ENOMEM; up (&usblp->sem); break; } diff -urN linux-2.4.25/drivers/usb/serial/ftdi_sio.c linux-2.4.26/drivers/usb/serial/ftdi_sio.c --- linux-2.4.25/drivers/usb/serial/ftdi_sio.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/ftdi_sio.c 2004-04-14 06:05:34.000000000 -0700 @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (09/Feb/2004) Ian Abbott + * Changed full name of USB-UIRT device to avoid "/" character. + * Added FTDI's alternate PID (0x6006) for FT232/245 devices. + * Added PID for "ELV USB Module UO100" from Stefan Frings. + * * (21/Oct/2003) Ian Abbott * Renamed some VID/PID macros for Matrix Orbital and Perle Systems * devices. Removed Matrix Orbital and Perle Systems devices from the @@ -272,8 +277,12 @@ static struct usb_device_id id_table_8U232AM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) }, @@ -337,12 +346,15 @@ { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, { } /* Terminating entry */ }; static struct usb_device_id id_table_FT232BM [] = { + { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) }, @@ -415,6 +427,7 @@ { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -432,9 +445,13 @@ static __devinitdata struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, + { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, @@ -508,6 +525,7 @@ { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, { } /* Terminating entry */ }; @@ -652,7 +670,7 @@ static struct usb_serial_device_type ftdi_USB_UIRT_device = { .owner = THIS_MODULE, - .name = "USB-UIRT Infrared Receiver/Transmitter", + .name = "USB-UIRT Infrared Tranceiver", .id_table = id_table_USB_UIRT, .num_interrupt_in = 0, .num_bulk_in = 1, @@ -1325,15 +1343,16 @@ /* drop RTS */ if (set_rts(port, LOW) < 0) { err("Error from RTS LOW urb"); - } - /* shutdown our bulk read */ - if (port->read_urb) { - usb_unlink_urb (port->read_urb); } - /* unlink the running write urbs */ - - } /* Note change no line is hupcl is off */ + + /* shutdown our bulk read */ + if (port->read_urb) { + if(usb_unlink_urb (port->read_urb)<0) + err("Error unlinking urb"); + } + /* unlink the running write urbs */ + } /* if (serial->dev) */ diff -urN linux-2.4.25/drivers/usb/serial/ftdi_sio.h linux-2.4.26/drivers/usb/serial/ftdi_sio.h --- linux-2.4.25/drivers/usb/serial/ftdi_sio.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/ftdi_sio.h 2004-04-14 06:05:34.000000000 -0700 @@ -25,10 +25,13 @@ #define FTDI_VID 0x0403 /* Vendor Id */ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ +#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ +/* www.irtrans.de device */ +#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ @@ -58,6 +61,12 @@ #define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ #define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ +/* Interbiometrics USB I/O Board */ +/* Developed for Interbiometrics by Rudolf Gugler */ +#define INTERBIOMETRICS_VID 0x1209 +#define INTERBIOMETRICS_IOBOARD_PID 0x1002 +#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006 + /* * The following are the values for the Perle Systems * UltraPort USB serial converters @@ -132,6 +141,9 @@ /* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */ #define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ +/* ELV USB Module UO100 (PID sent by Stefan Frings) */ +#define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */ + /* * Definitions for ID TECH (www.idt-net.com) devices */ diff -urN linux-2.4.25/drivers/usb/serial/io_edgeport.c linux-2.4.26/drivers/usb/serial/io_edgeport.c --- linux-2.4.25/drivers/usb/serial/io_edgeport.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/io_edgeport.c 2004-04-14 06:05:35.000000000 -0700 @@ -1760,7 +1760,7 @@ if (arg & TIOCM_RTS) mcr |= MCR_RTS; if (arg & TIOCM_DTR) - mcr |= MCR_RTS; + mcr |= MCR_DTR; if (arg & TIOCM_LOOP) mcr |= MCR_LOOPBACK; break; @@ -1769,7 +1769,7 @@ if (arg & TIOCM_RTS) mcr &= ~MCR_RTS; if (arg & TIOCM_DTR) - mcr &= ~MCR_RTS; + mcr &= ~MCR_DTR; if (arg & TIOCM_LOOP) mcr &= ~MCR_LOOPBACK; break; diff -urN linux-2.4.25/drivers/usb/serial/pl2303.c linux-2.4.26/drivers/usb/serial/pl2303.c --- linux-2.4.25/drivers/usb/serial/pl2303.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/pl2303.c 2004-04-14 06:05:35.000000000 -0700 @@ -390,7 +390,7 @@ { struct termios tmp_termios; struct usb_serial *serial = port->serial; - unsigned char buf[10]; + unsigned char *buf; int result; if (port_paranoia_check (port, __FUNCTION__)) @@ -401,6 +401,10 @@ usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); + buf = kmalloc(10, GFP_KERNEL); + if (buf==NULL) + return -ENOMEM; + #define FISH(a,b,c,d) \ result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \ b, a, c, d, buf, 1, 100); \ @@ -420,6 +424,8 @@ FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + kfree(buf); + /* Setup termios */ if (port->tty) { pl2303_set_termios (port, &tmp_termios); diff -urN linux-2.4.25/drivers/usb/serial/visor.c linux-2.4.26/drivers/usb/serial/visor.c --- linux-2.4.25/drivers/usb/serial/visor.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/visor.c 2004-04-14 06:05:35.000000000 -0700 @@ -215,6 +215,7 @@ { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, + { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { } /* Terminating entry */ }; @@ -247,6 +248,7 @@ { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, + { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { } /* Terminating entry */ }; diff -urN linux-2.4.25/drivers/usb/serial/visor.h linux-2.4.26/drivers/usb/serial/visor.h --- linux-2.4.25/drivers/usb/serial/visor.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/serial/visor.h 2004-04-14 06:05:35.000000000 -0700 @@ -50,6 +50,9 @@ #define GARMIN_VENDOR_ID 0x091E #define GARMIN_IQUE_3600_ID 0x0004 +#define ACEECA_VENDOR_ID 0x4766 +#define ACEECA_MEZ1000_ID 0x0001 + /**************************************************************************** * Handspring Visor Vendor specific request codes (bRequest values) * A big thank you to Handspring for providing the following information. diff -urN linux-2.4.25/drivers/usb/storage/datafab.c linux-2.4.26/drivers/usb/storage/datafab.c --- linux-2.4.25/drivers/usb/storage/datafab.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.26/drivers/usb/storage/datafab.c 2004-04-14 06:05:35.000000000 -0700 @@ -695,20 +695,24 @@ } if (srb->cmnd[0] == READ_CAPACITY) { + unsigned int max_sector; + info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec rc = datafab_id_device(us, info); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", + US_DEBUGP("datafab_transport: READ_CAPACITY: " + "%ld sectors, %ld bytes per sector\n", info->sectors, info->ssize); // build the reply // - ptr[0] = (info->sectors >> 24) & 0xFF; - ptr[1] = (info->sectors >> 16) & 0xFF; - ptr[2] = (info->sectors >> 8) & 0xFF; - ptr[3] = (info->sectors) & 0xFF; + max_sector = info->sectors - 1; + ptr[0] = (max_sector >> 24) & 0xFF; + ptr[1] = (max_sector >> 16) & 0xFF; + ptr[2] = (max_sector >> 8) & 0xFF; + ptr[3] = (max_sector) & 0xFF; ptr[4] = (info->ssize >> 24) & 0xFF; ptr[5] = (info->ssize >> 16) & 0xFF; diff -urN linux-2.4.25/drivers/usb/storage/scsiglue.c linux-2.4.26/drivers/usb/storage/scsiglue.c --- linux-2.4.25/drivers/usb/storage/scsiglue.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.26/drivers/usb/storage/scsiglue.c 2004-04-14 06:05:35.000000000 -0700 @@ -213,9 +213,14 @@ static int device_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + int rc; US_DEBUGP("device_reset() called\n" ); - return us->transport_reset(us); + + spin_unlock_irq(&io_request_lock); + rc = us->transport_reset(us); + spin_lock_irq(&io_request_lock); + return rc; } /* This resets the device port, and simulates the device diff -urN linux-2.4.25/drivers/usb/storage/unusual_devs.h linux-2.4.26/drivers/usb/storage/unusual_devs.h --- linux-2.4.25/drivers/usb/storage/unusual_devs.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/storage/unusual_devs.h 2004-04-14 06:05:35.000000000 -0700 @@ -249,7 +249,7 @@ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", "Memorystick NW-MS7", - US_SC_UFI, US_PR_CB, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), #ifdef CONFIG_USB_STORAGE_ISD200 @@ -278,6 +278,13 @@ "Memorystick MSC-U01N", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN ), + +/* Submitted by Michal Mlotek */ +UNUSUAL_DEV( 0x054c, 0x0058, 0x0000, 0x9999, + "Sony", + "PEG N760c Memorystick", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY ), UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999, "Sony", @@ -353,7 +360,7 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, "Lexar", "USB CF Reader", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Reported by Carlos Villegas @@ -370,7 +377,7 @@ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, "", "USB TO IDE", - US_SC_SCSI, US_PR_DEVICE, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), /* Reported by Peter Marks @@ -628,6 +635,17 @@ US_SC_DEVICE, US_PR_BULK, NULL, US_FL_MODE_XLATE ), +/* Entry needed for flags. Moreover, all devices with this ID use + * bulk-only transport, but _some_ falsely report Control/Bulk instead. + * One example is "Trumpion Digital Research MYMP3". + * Submitted by Bjoern Brill + */ +UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, + "Trumpion", + "t33520 USB Flash Card Controller", + US_SC_DEVICE, US_PR_BULK, NULL, + US_FL_MODE_XLATE), + /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, "Trumpion", @@ -667,15 +685,9 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), -/* This entry from in the Debian mailing list */ -UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff, - "Pentax", - "Optio 330GS", - US_SC_8070, US_PR_CB, NULL, - US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ), /* Submitted by Per Winkvist */ -UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, +UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff, "Pentax", "Optio S/S4", US_SC_DEVICE, US_PR_DEVICE, NULL, diff -urN linux-2.4.25/drivers/usb/usbnet.c linux-2.4.26/drivers/usb/usbnet.c --- linux-2.4.25/drivers/usb/usbnet.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.26/drivers/usb/usbnet.c 2004-04-14 06:05:36.000000000 -0700 @@ -2594,7 +2594,11 @@ // Hawking UF200, TrendNet TU2-ET100 USB_DEVICE (0x07b8, 0x420a), .driver_info = (unsigned long) &hawking_uf200_info, -}, +}, { + // ATEN UC210T + USB_DEVICE (0x0557, 0x2009), + .driver_info = (unsigned long) &ax8817x_info, +}, #endif #ifdef CONFIG_USB_BELKIN @@ -2724,6 +2728,15 @@ .bInterfaceSubClass = 0x0a, .bInterfaceProtocol = 0x00, .driver_info = (unsigned long) &zaurus_pxa_info, +}, { + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x04DD, + .idProduct = 0x9032, /* SL-6000 */ + .bInterfaceClass = 0x02, + .bInterfaceSubClass = 0x0a, + .bInterfaceProtocol = 0x00, + .driver_info = (unsigned long) &zaurus_pxa_info, }, #endif diff -urN linux-2.4.25/drivers/usb/w9968cf.c linux-2.4.26/drivers/usb/w9968cf.c --- linux-2.4.25/drivers/usb/w9968cf.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/usb/w9968cf.c 2004-04-14 06:05:37.000000000 -0700 @@ -2943,7 +2943,7 @@ return -ENODEV; } - if (cam->users) { + while (cam->users) { DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.", symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { @@ -3632,7 +3632,7 @@ if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; - if (tuner.tuner != 0); + if (tuner.tuner != 0) return -EINVAL; strcpy(tuner.name, "no_tuner"); diff -urN linux-2.4.25/drivers/video/amifb.c linux-2.4.26/drivers/video/amifb.c --- linux-2.4.25/drivers/video/amifb.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.26/drivers/video/amifb.c 2004-04-14 06:05:37.000000000 -0700 @@ -807,7 +807,7 @@ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP }, { /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ - "ntsc-lace", 60, 640, TAG_HIRES, 106, 86, 88, 33, 76, 4, + "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP }, { /* 640x256, 15 kHz, 50 Hz (PAL) */ @@ -902,7 +902,7 @@ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP }, { /* 1024x800, 15 Hz */ - "a2024-15", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP } #endif diff -urN linux-2.4.25/drivers/video/pm3fb.c linux-2.4.26/drivers/video/pm3fb.c --- linux-2.4.25/drivers/video/pm3fb.c 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.26/drivers/video/pm3fb.c 2004-04-14 06:05:38.000000000 -0700 @@ -19,6 +19,7 @@ * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ * * CHANGELOG: + * Wed Nov 13 11:19:34 MET 2002, v 1.4.11C: option flatpanel: wasn't available in module, fixed. * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. @@ -3756,6 +3757,8 @@ MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT); MODULE_PARM_DESC(forcesize, "force specified memory size"); +MODULE_PARM(flatpanel, PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +MODULE_PARM_DESC(flatpanel, "flatpanel (LCD) support (preliminary)"); /* MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") MODULE_GENERIC_TABLE(gtype,name) @@ -3800,6 +3803,11 @@ sprintf(ts, ",depth:%d:%d", i, depth[i]); strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); } + if (flatpanel[i]) + { + sprintf(ts, ",flatpanel:%d:", i); + strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); + } } g_options[PM3_OPTIONS_SIZE - 1] = '\0'; DPRINTK(1, "pm3fb use options: %s\n", g_options); diff -urN linux-2.4.25/drivers/video/radeonfb.c linux-2.4.26/drivers/video/radeonfb.c --- linux-2.4.25/drivers/video/radeonfb.c 2003-08-25 04:44:42.000000000 -0700 +++ linux-2.4.26/drivers/video/radeonfb.c 2004-04-14 06:05:39.000000000 -0700 @@ -202,6 +202,8 @@ RADEON_If, RADEON_Ig, RADEON_Y_, + RADEON_Ya, + RADEON_Yd, RADEON_Ld, RADEON_Le, RADEON_Lf, @@ -261,6 +263,8 @@ { "9000 If", RADEON_RV250 }, { "9000 Ig", RADEON_RV250 }, { "9200 Y", RADEON_RV280 }, + { "9200 Ya", RADEON_RV280 }, + { "9200 Yd", RADEON_RV280 }, { "M9 Ld", RADEON_M9 }, { "M9 Le", RADEON_M9 }, { "M9 Lf", RADEON_M9 }, @@ -326,6 +330,8 @@ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NH, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NH}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_NI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_NI}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Y_, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Y_}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Ya, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Ya}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_Yd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_Yd}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AD}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AP}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_AR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RADEON_AR}, diff -urN linux-2.4.25/drivers/video/sis/300vtbl.h linux-2.4.26/drivers/video/sis/300vtbl.h --- linux-2.4.25/drivers/video/sis/300vtbl.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/300vtbl.h 2004-04-14 06:05:39.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -52,20 +49,7 @@ * */ -typedef struct _SiS300_StStruct -{ - UCHAR St_ModeID; - USHORT St_ModeFlag; - UCHAR St_StTableIndex; - UCHAR St_CRT2CRTC; - UCHAR St_ResInfo; - UCHAR VB_StTVFlickerIndex; - UCHAR VB_StTVEdgeIndex; - UCHAR VB_StTVYFilterIndex; - UCHAR St_PDC; -} SiS300_StStruct; - -static const SiS300_StStruct SiS300_SModeIDTable[] = +static const SiS_StStruct SiS300_SModeIDTable[] = { {0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00, 0}, {0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00, 0}, @@ -89,206 +73,168 @@ {0xff, 0, 0, 0, 0, 0, 0, 0, 0} }; -typedef struct _SiS300_ExtStruct +static const SiS_ExtStruct SiS300_EModeIDTable[] = { - UCHAR Ext_ModeID; - USHORT Ext_ModeFlag; - UCHAR Ext_ModeOffset; - USHORT Ext_VESAID; - UCHAR Ext_RESINFO; - UCHAR VB_ExtTVFlickerIndex; - UCHAR VB_ExtTVEdgeIndex; - UCHAR VB_ExtTVYFilterIndex; - UCHAR VB_ExtTVYFilterIndexROM661; - UCHAR REFindex; -} SiS300_ExtStruct; - -static const SiS300_ExtStruct SiS300_EModeIDTable[] = -{ - {0x6a,0x2212,0x04,0x0102,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x? */ - {0x2e,0x0a1b,0x03,0x0101,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, - {0x2f,0x021b,0x03,0x0100,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x8 */ - {0x30,0x2a1b,0x04,0x0103,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, - {0x31,0x0a1b,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x8 */ - {0x32,0x2a1b,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x8 */ - {0x33,0x0a1d,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x16 */ - {0x34,0x2a1d,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x16 */ - {0x35,0x0a1f,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x32 */ - {0x36,0x2a1f,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x32 */ - {0x37,0x0212,0x05,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, /* 1024x768x? */ - {0x38,0x0a1b,0x05,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x06,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */ - {0x3c,0x063b,0x07,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, - {0x3d,0x067d,0x07,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, - {0x40,0x921c,0x00,0x010d,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x15 */ - {0x41,0x921d,0x00,0x010e,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x16 */ - {0x43,0x0a1c,0x03,0x0110,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, - {0x44,0x0a1d,0x03,0x0111,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, - {0x46,0x2a1c,0x04,0x0113,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x15 */ - {0x47,0x2a1d,0x04,0x0114,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x16 */ - {0x49,0x0a3c,0x05,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, - {0x4a,0x0a3d,0x05,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, - {0x4c,0x0e7c,0x06,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, - {0x4d,0x0e7d,0x06,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, - {0x50,0x921b,0x00,0x0132,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x8 */ - {0x51,0xb21b,0x01,0x0133,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x8 */ - {0x52,0x921b,0x02,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x8 */ - {0x56,0x921d,0x00,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x16 */ - {0x57,0xb21d,0x01,0x0136,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x16 */ - {0x58,0x921d,0x02,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x16 */ - {0x59,0x921b,0x00,0x0138,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x8 */ - {0x5c,0x921f,0x02,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x32 */ - {0x5d,0x021d,0x03,0x0139,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x16 */ - {0x5e,0x021f,0x03,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x32 */ - {0x62,0x0a3f,0x03,0x013a,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, - {0x63,0x2a3f,0x04,0x013b,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x32 */ - {0x64,0x0a7f,0x05,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, - {0x65,0x0eff,0x06,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, - {0x66,0x06ff,0x07,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, - {0x68,0x067b,0x08,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, - {0x69,0x06fd,0x08,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, - {0x6b,0x07ff,0x08,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, - {0x6c,0x067b,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28}, /* 2048x1536x8 - not in BIOS! */ - {0x6d,0x06fd,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28}, /* 2048x1536x16 - not in BIOS! */ - {0x70,0x2a1b,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x8 */ - {0x71,0x0a1b,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x8 */ - {0x74,0x0a1d,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x16 */ - {0x75,0x0e3d,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x16 */ - {0x76,0x2a1f,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x32 */ - {0x77,0x0a3f,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x32 */ - {0x78,0x0eff,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x32 */ - {0x79,0x0e3b,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x8 */ - {0x7a,0x2a1d,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x16 */ - {0x7c,0x0a3b,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x8 */ - {0x7d,0x0a7d,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x16 */ - {0x7e,0x0aff,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x32 */ - {0x20,0x0a1b,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, /* 1024x600 */ - {0x21,0x0a3d,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, - {0x22,0x0a7f,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, - {0x23,0x0a1b,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, /* 1152x768 */ - {0x24,0x0a3d,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, - {0x25,0x0a7f,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, - {0x29,0x0e1b,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, /* 1152x864 */ - {0x2a,0x0e3d,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, - {0x2b,0x0e7f,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, - {0x39,0x2a1b,0x0d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, /* 848x480 */ - {0x3b,0x2a3d,0x0d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, - {0x3e,0x2a7f,0x0d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, - {0x3f,0x2a1b,0x0d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, /* 856x480 */ - {0x42,0x2a3d,0x0d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, - {0x45,0x2a7f,0x0d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, - {0x48,0x223b,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, /* 1360x768 */ - {0x4b,0x227d,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, - {0x4e,0x22ff,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, - {0x4f,0x921f,0x00,0x0000,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x32 */ - {0x53,0x921f,0x00,0x0000,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x32 */ - {0x54,0xb21f,0x01,0x0000,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x32 */ - {0x55,0x2e3b,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x768 */ - {0x5a,0x2e7d,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, - {0x5b,0x2eff,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, - {0x5f,0x2a1b,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x8 */ - {0x60,0x2a1d,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x16 */ - {0x61,0x2a1f,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x32 */ - {0x67,0x2e3b,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x8 (BARCO) */ - {0x6f,0x2e7d,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x16 (BARCO) */ - {0x72,0x2eff,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x32 (BARCO) */ - {0xff,0x0000,0x00,0xffff,0, 0x00,0x00,0x00,0x00,0x00} -}; - -typedef struct _SiS300_Ext2Struct -{ - USHORT Ext_InfoFlag; - UCHAR Ext_CRT1CRTC; /* Index in SiS300_CRT1Table */ - UCHAR Ext_CRTVCLK; /* Index in VCLK array */ - UCHAR Ext_CRT2CRTC; /* Index in LCD Paneltype arrays (&3f) */ - UCHAR ModeID; - USHORT XRes; - USHORT YRes; - UCHAR Ext_PDC; -} SiS300_Ext2Struct; + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, + {0x2f,0x021b,0x0100,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, + {0x31,0x0a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x8 */ + {0x32,0x2a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x8 */ + {0x33,0x0a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x16 */ + {0x34,0x2a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x16 */ + {0x35,0x0a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x00,0x00,0x11}, /* 720x480x32 */ + {0x36,0x2a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x00,0x00,0x12}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */ + {0x3c,0x063b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, + {0x3d,0x067d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, + {0x40,0x921c,0x010d,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x15 */ + {0x41,0x921d,0x010e,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x15 */ + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, + {0x50,0x921b,0x0132,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x8 */ + {0x51,0xb21b,0x0133,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x8 */ + {0x52,0x921b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x8 */ + {0x56,0x921d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x16 */ + {0x57,0xb21d,0x0136,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x16 */ + {0x58,0x921d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x16 */ + {0x59,0x921b,0x0138,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x8 */ + {0x5c,0x921f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x26}, /* 512x384x32 */ + {0x5d,0x021d,0x0139,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x16 */ + {0x5e,0x021f,0x0000,SIS_RI_640x400, 0x00,0x00,0x00,0x00,0x10}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x00,0x00,0x08}, + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x00,0x00,0x00}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13}, + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, + {0x66,0x06ff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, + {0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27}, + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28}, /* 2048x1536x8 - not in BIOS! */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28}, /* 2048x1536x16 - not in BIOS! */ + {0x70,0x2a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x8 */ + {0x71,0x0a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x8 */ + {0x74,0x0a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x16 */ + {0x75,0x0e3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x16 */ + {0x76,0x2a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x32 */ + {0x77,0x0a3f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30}, /* 1024x576x32 */ + {0x78,0x0eff,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x32 */ + {0x79,0x0e3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33}, /* 1280x720x8 */ + {0x7a,0x2a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x00,0x2d}, /* 800x480x16 */ + {0x7c,0x0a3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x8 */ + {0x7d,0x0a7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x16 */ + {0x7e,0x0aff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29}, /* 1280x960x32 */ + {0x20,0x0a1b,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, /* 1024x600 */ + {0x21,0x0a3d,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, + {0x22,0x0a7f,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b}, + {0x23,0x0a1b,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, /* 1152x768 */ + {0x24,0x0a3d,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, + {0x25,0x0a7f,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c}, + {0x29,0x0e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, /* 1152x864 */ + {0x2a,0x0e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, + {0x2b,0x0e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36}, + {0x39,0x2a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, /* 848x480 */ + {0x3b,0x2a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, + {0x3e,0x2a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x38}, + {0x3f,0x2a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, /* 856x480 */ + {0x42,0x2a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, + {0x45,0x2a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x3a}, + {0x48,0x223b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, /* 1360x768 */ + {0x4b,0x227d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, + {0x4e,0x22ff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c}, + {0x4f,0x921f,0x0000,SIS_RI_320x200, 0x00,0x00,0x00,0x00,0x23}, /* 320x200x32 */ + {0x53,0x921f,0x0000,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x24}, /* 320x240x32 */ + {0x54,0xb21f,0x0000,SIS_RI_400x300, 0x00,0x00,0x00,0x00,0x25}, /* 400x300x32 */ + {0x55,0x2e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x768 */ + {0x5a,0x2e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, + {0x5b,0x2eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d}, + {0x5f,0x2a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x8 */ + {0x60,0x2a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x16 */ + {0x61,0x2a1f,0x0000,SIS_RI_768x576, 0x00,0x00,0x00,0x00,0x3e}, /* 768x576x32 */ + {0x67,0x2e3b,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x8 (BARCO) */ + {0x6f,0x2e7d,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x16 (BARCO) */ + {0x72,0x2eff,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f}, /* 1360x1024x32 (BARCO) */ + {0xff,0x0000,0xffff,0, 0x00,0x00,0x00,0x00,0x00} +}; -static const SiS300_Ext2Struct SiS300_RefIndex[] = +static const SiS_Ext2Struct SiS300_RefIndex[] = { - {0x085f,0x0d,0x03,0x05,0x6a, 800, 600, 0}, /* 00 */ - {0x0467,0x0e,0x44,0x05,0x6a, 800, 600, 0}, /* 01 */ - {0x0067,0x0f,0x07,0x48,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */ - {0x0067,0x10,0x06,0x8b,0x6a, 800, 600, 0}, /* 03 */ - {0x0147,0x11,0x08,0x00,0x6a, 800, 600, 0}, /* 04 */ - {0x0147,0x12,0x0c,0x00,0x6a, 800, 600, 0}, /* 05 */ - {0x0047,0x11,0x4e,0x00,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */ - {0x0047,0x11,0x13,0x00,0x6a, 800, 600, 0}, /* 07 */ - {0xc85f,0x05,0x00,0x04,0x2e, 640, 480, 0}, /* 08 */ - {0xc067,0x06,0x02,0x04,0x2e, 640, 480, 0}, /* 09 */ - {0xc067,0x07,0x02,0x47,0x2e, 640, 480, 0}, /* 0a */ - {0xc067,0x08,0x03,0x8a,0x2e, 640, 480, 0}, /* 0b */ - {0xc047,0x09,0x05,0x00,0x2e, 640, 480, 0}, /* 0c */ - {0xc047,0x0a,0x08,0x00,0x2e, 640, 480, 0}, /* 0d */ - {0xc047,0x0b,0x0a,0x00,0x2e, 640, 480, 0}, /* 0e */ - {0xc047,0x0c,0x10,0x00,0x2e, 640, 480, 0}, /* 0f */ - {0x487f,0x04,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */ - {0xc04f,0x31,0x01,0x06,0x31, 720, 480, 0}, /* 11 */ - {0x004f,0x32,0x03,0x06,0x32, 720, 576, 0}, /* 12 */ - {0x0187,0x15,0x05,0x00,0x37,1024, 768, 0}, /* 13 */ - {0xc877,0x16,0x09,0x06,0x37,1024, 768, 0}, /* 14 */ - {0xc067,0x17,0x0b,0x49,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */ - {0x0267,0x18,0x0d,0x00,0x37,1024, 768, 0}, /* 16 */ - {0x0047,0x19,0x11,0x8c,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */ - {0x0047,0x1a,0x52,0x00,0x37,1024, 768, 0}, /* 18 */ - {0x0007,0x1b,0x16,0x00,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */ - {0x0387,0x1c,0x4d,0x00,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */ - {0x0077,0x1d,0x14,0x07,0x3a,1280,1024, 0}, /* 1b */ - {0x0047,0x1e,0x17,0x00,0x3a,1280,1024, 0}, /* 1c */ - {0x0007,0x1f,0x98,0x00,0x3a,1280,1024, 0}, /* 1d */ - {0x0007,0x20,0x59,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */ - {0x0007,0x21,0x5a,0x00,0x3c,1600,1200, 0}, /* 1f */ - {0x0007,0x22,0x1b,0x00,0x3c,1600,1200, 0}, /* 20 */ - {0x0007,0x23,0x1d,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */ - {0x0007,0x24,0x1e,0x00,0x3c,1600,1200, 0}, /* 22 */ - {0x407f,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */ - {0xc07f,0x01,0x00,0x04,0x50, 320, 240, 0}, /* 24 */ - {0x0077,0x02,0x04,0x05,0x51, 400, 300, 0}, /* 25 */ - {0xc877,0x03,0x09,0x06,0x52, 512, 384, 0}, /* 26 */ /* was c077 */ - {0x8207,0x25,0x1f,0x00,0x68,1920,1440, 0}, /* 27 */ - {0x0007,0x26,0x20,0x00,0x6c,2048,1536, 0}, /* 28 */ - {0x0067,0x27,0x14,0x08,0x6e,1280, 960, 0}, /* 29 - TW: 1280x960-60 */ - {0x0027,0x45,0x3c,0x08,0x6e,1280, 960, 0}, /* 2a - TW: 1280x960-85 */ - {0xc077,0x33,0x09,0x06,0x20,1024, 600, 0}, /* 2b */ - {0xc077,0x34,0x0b,0x06,0x23,1152, 768, 0}, /* 2c */ /* VCLK 0x09 */ - {0x0057,0x35,0x27,0x08,0x70, 800, 480, 0}, /* 2d */ - {0x0047,0x36,0x37,0x08,0x70, 800, 480, 0}, /* 2e */ - {0x0047,0x37,0x08,0x08,0x70, 800, 480, 0}, /* 2f */ - {0x0057,0x38,0x09,0x09,0x71,1024, 576, 0}, /* 30 */ - {0x0047,0x39,0x38,0x09,0x71,1024, 576, 0}, /* 31 */ - {0x0047,0x3a,0x11,0x09,0x71,1024, 576, 0}, /* 32 */ - {0x0057,0x3b,0x39,0x0a,0x75,1280, 720, 0}, /* 33 */ - {0x0047,0x3c,0x3a,0x0a,0x75,1280, 720, 0}, /* 34 */ - {0x0007,0x3d,0x3b,0x0a,0x75,1280, 720, 0}, /* 35 */ - {0x0047,0x3e,0x34,0x06,0x29,1152, 864, 0}, /* 36 1152x864-75Hz */ - {0x0047,0x44,0x3a,0x06,0x29,1152, 864, 0}, /* 37 1152x864-85Hz */ - {0x00c7,0x3f,0x28,0x00,0x39, 848, 480, 0}, /* 38 848x480-38Hzi */ - {0xc067,0x40,0x3d,0x0b,0x39, 848, 480, 0}, /* 39 848x480-60Hz */ - {0x00c7,0x41,0x28,0x00,0x3f, 856, 480, 0}, /* 3a 856x480-38Hzi */ - {0xc047,0x42,0x28,0x00,0x3f, 856, 480, 0}, /* 3b 856x480-60Hz */ - {0x0067,0x43,0x3e,0x0c,0x48,1360, 768, 0}, /* 3c 1360x768-60Hz */ - {0x0077,0x46,0x3f,0x08,0x55,1280, 768, 0}, /* 3d 1280x768-60Hz */ - {0x004f,0x47,0x03,0x06,0x5f, 768, 576, 0}, /* 3e 768x576 */ - {0x0027,0x48,0x13,0x08,0x67,1360,1024, 0}, /* 3f 1360x1024-59Hz (BARCO1366 only) */ - {0xffff, 0, 0, 0, 0, 0, 0, 0} -}; - -typedef struct _SiS_VBModeIDTableStruct -{ - UCHAR ModeID; - UCHAR VB_TVDelayIndex; - UCHAR VB_TVFlickerIndex; - UCHAR VB_TVPhaseIndex; - UCHAR VB_TVYFilterIndex; - UCHAR VB_LCDDelayIndex; - UCHAR _VB_LCDHIndex; - UCHAR _VB_LCDVIndex; -}SiS_VBModeIDTableStruct; + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0}, /* 00 */ + {0x0467,0x0e,0x44,0x05,0x05,0x6a, 800, 600, 0}, /* 01 */ + {0x0067,0x0f,0x07,0x48,0x00,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */ + {0x0067,0x10,0x06,0x8b,0x00,0x6a, 800, 600, 0}, /* 03 */ + {0x0147,0x11,0x08,0x00,0x00,0x6a, 800, 600, 0}, /* 04 */ + {0x0147,0x12,0x0c,0x00,0x00,0x6a, 800, 600, 0}, /* 05 */ + {0x0047,0x11,0x4e,0x00,0x00,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */ + {0x0047,0x11,0x13,0x00,0x00,0x6a, 800, 600, 0}, /* 07 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0}, /* 08 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0}, /* 09 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0}, /* 0a */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0}, /* 0b */ + {0xc047,0x09,0x05,0x00,0x00,0x2e, 640, 480, 0}, /* 0c */ + {0xc047,0x0a,0x08,0x00,0x00,0x2e, 640, 480, 0}, /* 0d */ + {0xc047,0x0b,0x0a,0x00,0x00,0x2e, 640, 480, 0}, /* 0e */ + {0xc047,0x0c,0x10,0x00,0x00,0x2e, 640, 480, 0}, /* 0f */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */ + {0xc04f,0x31,0x01,0x06,0x00,0x31, 720, 480, 0}, /* 11 */ + {0x004f,0x32,0x03,0x06,0x00,0x32, 720, 576, 0}, /* 12 */ + {0x0187,0x15,0x05,0x00,0x00,0x37,1024, 768, 0}, /* 13 */ + {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0}, /* 14 */ + {0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */ + {0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0}, /* 16 */ + {0x0047,0x19,0x11,0x8c,0x00,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */ + {0x0047,0x1a,0x52,0x00,0x00,0x37,1024, 768, 0}, /* 18 */ + {0x0007,0x1b,0x16,0x00,0x00,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */ + {0x0387,0x1c,0x4d,0x00,0x00,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */ + {0x0077,0x1d,0x14,0x07,0x00,0x3a,1280,1024, 0}, /* 1b */ + {0x0047,0x1e,0x17,0x00,0x00,0x3a,1280,1024, 0}, /* 1c */ + {0x0007,0x1f,0x98,0x00,0x00,0x3a,1280,1024, 0}, /* 1d */ + {0x0007,0x20,0x59,0x00,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */ + {0x0007,0x21,0x5a,0x00,0x00,0x3c,1600,1200, 0}, /* 1f */ + {0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0}, /* 20 */ + {0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */ + {0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0}, /* 22 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0}, /* 24 */ + {0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0}, /* 25 */ + {0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0}, /* 26 */ /* was c077 */ + {0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0}, /* 27 */ + {0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0}, /* 28 */ + {0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0}, /* 29 - 1280x960-60 */ + {0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0}, /* 2a - 1280x960-85 */ + {0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0}, /* 2b */ + {0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0}, /* 2c */ /* VCLK 0x09 */ + {0x0057,0x35,0x27,0x08,0x00,0x70, 800, 480, 0}, /* 2d */ + {0x0047,0x36,0x37,0x08,0x00,0x70, 800, 480, 0}, /* 2e */ + {0x0047,0x37,0x08,0x08,0x00,0x70, 800, 480, 0}, /* 2f */ + {0x0057,0x38,0x09,0x09,0x00,0x71,1024, 576, 0}, /* 30 */ + {0x0047,0x39,0x38,0x09,0x00,0x71,1024, 576, 0}, /* 31 */ + {0x0047,0x3a,0x11,0x09,0x00,0x71,1024, 576, 0}, /* 32 */ + {0x0057,0x3b,0x39,0x0a,0x00,0x75,1280, 720, 0}, /* 33 */ + {0x0047,0x3c,0x3a,0x0a,0x00,0x75,1280, 720, 0}, /* 34 */ + {0x0007,0x3d,0x3b,0x0a,0x00,0x75,1280, 720, 0}, /* 35 */ + {0x0047,0x3e,0x34,0x06,0x00,0x29,1152, 864, 0}, /* 36 1152x864-75Hz */ + {0x0047,0x44,0x3a,0x06,0x00,0x29,1152, 864, 0}, /* 37 1152x864-85Hz */ + {0x00c7,0x3f,0x28,0x00,0x00,0x39, 848, 480, 0}, /* 38 848x480-38Hzi */ + {0xc067,0x40,0x3d,0x0b,0x0b,0x39, 848, 480, 0}, /* 39 848x480-60Hz */ + {0x00c7,0x41,0x28,0x00,0x00,0x3f, 856, 480, 0}, /* 3a 856x480-38Hzi */ + {0xc047,0x42,0x28,0x00,0x00,0x3f, 856, 480, 0}, /* 3b 856x480-60Hz */ + {0x0067,0x43,0x3e,0x0c,0x0b,0x48,1360, 768, 0}, /* 3c 1360x768-60Hz */ + {0x0077,0x46,0x3f,0x08,0x00,0x55,1280, 768, 0}, /* 3d 1280x768-60Hz */ + {0x004f,0x47,0x03,0x06,0x00,0x5f, 768, 576, 0}, /* 3e 768x576 */ + {0x0027,0x48,0x13,0x08,0x08,0x67,1360,1024, 0}, /* 3f 1360x1024-59Hz (BARCO1366 only) */ + {0xffff, 0, 0, 0, 0, 0, 0, 0, 0} +}; -static const SiS_VBModeIDTableStruct SiS300_VBModeIDTable[] = +static const SiS_VBModeStruct SiS300_VBModeIDTable[] = { {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, @@ -355,12 +301,7 @@ {0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }; -typedef struct _SiS300_CRT1TableStruct -{ - UCHAR CR[17]; -} SiS300_CRT1TableStruct; - -static const SiS300_CRT1TableStruct SiS300_CRT1Table[] = +static const SiS_CRT1TableStruct SiS300_CRT1Table[] = { #if 1 {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, /* 0x00 - 320x200 */ @@ -625,13 +566,7 @@ 0x00}} /* 0x48 */ }; -typedef struct _SiS300_MCLKDataStruct -{ - UCHAR SR28,SR29,SR2A; - USHORT CLOCK; -} SiS300_MCLKDataStruct; - -static const SiS300_MCLKDataStruct SiS300_MCLKData_630[] = +static const SiS_MCLKDataStruct SiS300_MCLKData_630[] = { { 0x5a,0x64,0x80, 66}, { 0xb3,0x45,0x80, 83}, @@ -643,7 +578,7 @@ { 0x37,0x61,0x80,100} }; -static const SiS300_MCLKDataStruct SiS300_MCLKData_300[] = +static const SiS_MCLKDataStruct SiS300_MCLKData_300[] = { { 0x68,0x43,0x80,125}, { 0x68,0x43,0x80,125}, @@ -655,13 +590,7 @@ { 0x37,0x61,0x80,100} }; -typedef struct _SiS300_VCLKDataStruct -{ - UCHAR SR2B,SR2C; - USHORT CLOCK; -} SiS300_VCLKDataStruct; - -static const SiS300_VCLKDataStruct SiS300_VCLKData[] = +static SiS_VCLKDataStruct SiS300_VCLKData[] = { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -736,14 +665,7 @@ { 0x37,0x61,100}, /* 0x43 */ /* 1280x960 LCD */ { 0xe3,0x9a,106}, /* 0x44 */ /* 1360x1024 - special for Barco iQ R300 */ { 0xe2,0x46,135}, /* 0x45 */ /* 1280x1024-75, better clock for VGA2 */ - { 0xff,0x00, 0} -}; - -static const UCHAR SiS300_ScreenOffset[] = -{ - 0x14,0x19,0x20,0x28,0x32,0x40,0x50, - 0x64,0x78,0x80,0x2d,0x35,0x48,0x35, - 0x55,0x30,0xff + { 0, 0, 0} /* 0x46 custom (will be filled out) */ }; #ifndef LINUX_XF86 @@ -789,12 +711,7 @@ static UCHAR SiS300_CR49[2]; #endif -typedef struct _SiS300_PanelDelayTblStruct -{ - UCHAR timer[2]; -} SiS300_PanelDelayTblStruct; - -static const SiS300_PanelDelayTblStruct SiS300_PanelDelayTbl[] = +static const SiS_PanelDelayTblStruct SiS300_PanelDelayTbl[] = { {{0x05,0xaa}}, {{0x05,0x14}}, @@ -815,7 +732,7 @@ }; #if 0 -static const SiS300_PanelDelayTblStruct SiS300_PanelDelayTblLVDS[] = +static const SiS_PanelDelayTblStruct SiS300_PanelDelayTblLVDS[] = { {{0x05,0xaa}}, {{0x05,0x14}}, @@ -840,28 +757,18 @@ /* SIS VIDEO BRIDGE ----------------------------------------- */ /**************************************************************/ -typedef struct _SiS300_LCDDataStruct +static const SiS_LCDDataStruct SiS300_St2LCD1024x768Data[] = { - USHORT RVBHCMAX; - USHORT RVBHCFACT; - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS300_LCDDataStruct; - -static const SiS300_LCDDataStruct SiS300_StLCD1024x768Data[] = -{ - { 66, 31, 992, 510,1320, 816}, - { 66, 31, 992, 510,1320, 816}, - { 176, 75, 900, 510,1320, 816}, - { 176, 75, 900, 510,1320, 816}, - { 66, 31, 992, 510,1320, 816}, - { 27, 16,1024, 650,1350, 832}, + { 62, 25, 800, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 32, 15, 930, 546,1344, 806}, + { 104, 45, 945, 496,1344, 806}, + { 62, 25, 800, 546,1344, 806}, + { 31, 18,1008, 624,1344, 806}, { 1, 1,1344, 806,1344, 806} }; -static const SiS300_LCDDataStruct SiS300_ExtLCD1024x768Data[] = +static const SiS_LCDDataStruct SiS300_ExtLCD1024x768Data[] = { { 12, 5, 896, 512,1344, 806}, { 12, 5, 896, 510,1344, 806}, @@ -878,30 +785,19 @@ { 1, 1,1344, 806,1344, 806} }; -static const SiS300_LCDDataStruct SiS300_St2LCD1024x768Data[] = +static const SiS_LCDDataStruct SiS300_St2LCD1280x1024Data[] = { - { 62, 25, 800, 546,1344, 806}, - { 32, 15, 930, 546,1344, 806}, - { 32, 15, 930, 546,1344, 806}, - { 104, 45, 945, 496,1344, 806}, - { 62, 25, 800, 546,1344, 806}, - { 31, 18,1008, 624,1344, 806}, - { 1, 1,1344, 806,1344, 806} -}; - -static const SiS300_LCDDataStruct SiS300_StLCD1280x1024Data[] = -{ - { 4, 1, 880, 510,1650,1088}, - { 4, 1, 880, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, { 176, 45, 900, 510,1650,1088}, { 176, 45, 900, 510,1650,1088}, - { 4, 1, 880, 510,1650,1088}, + { 22, 5, 800, 510,1650,1088}, { 13, 5,1024, 675,1560,1152}, { 16, 9,1266, 804,1688,1072}, { 1, 1,1688,1066,1688,1066} }; -static const SiS300_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = +static const SiS_LCDDataStruct SiS300_ExtLCD1280x1024Data[] = { { 211, 60,1024, 501,1688,1066}, { 211, 60,1024, 508,1688,1066}, @@ -913,74 +809,18 @@ { 1, 1,1688,1066,1688,1066} }; -static const SiS300_LCDDataStruct SiS300_St2LCD1280x1024Data[] = -{ - { 22, 5, 800, 510,1650,1088}, - { 22, 5, 800, 510,1650,1088}, - { 176, 45, 900, 510,1650,1088}, - { 176, 45, 900, 510,1650,1088}, - { 22, 5, 800, 510,1650,1088}, - { 13, 5,1024, 675,1560,1152}, - { 16, 9,1266, 804,1688,1072}, - { 1, 1,1688,1066,1688,1066} -}; - -static const SiS300_LCDDataStruct SiS300_NoScaleData1024x768[] = -{ - { 1, 1, 800, 449, 800, 449}, - { 1, 1, 800, 449, 800, 449}, - { 1, 1, 900, 449, 900, 449}, - { 1, 1, 900, 449, 900, 449}, - { 1, 1, 800, 525, 800, 525}, - { 1, 1,1056, 628,1056, 628}, - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1688,1066,1688,1066} -}; - -static const SiS300_LCDDataStruct SiS300_NoScaleData1280x1024[] = /* TW: Fake */ -{ - { 1, 1, 800, 449, 800, 449}, - { 1, 1, 800, 449, 800, 449}, - { 1, 1, 900, 449, 900, 449}, - { 1, 1, 900, 449, 900, 449}, - { 1, 1, 800, 525, 800, 525}, - { 1, 1,1056, 628,1056, 628}, - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1688,1066,1688,1066} -}; - -typedef struct _SiS300_Part2PortTblStruct -{ - UCHAR CR[12]; -} SiS300_Part2PortTblStruct; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] = +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] = { /* VESA Timing */ - {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, - {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_1[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_1[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}, + {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}} }; -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] = +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] = { /* Non-VESA */ {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}, @@ -991,38 +831,23 @@ {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}} }; -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] = -{ +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] = +{ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} }; -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_2[] = +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] = { - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_2[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] = -{ /* TW: Temporary data, invalid */ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} }; -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_3[] = -{ /* TW: Temporary data, invalid */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] = +{ + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} }; -static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_3[] = -{ /* TW: Temporary data, invalid */ +static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] = +{ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} }; @@ -1030,15 +855,7 @@ /* LVDS/Chrontel -------------------------------------------- */ /**************************************************************/ -typedef struct _SiS300_LVDSDataStruct -{ - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS300_LVDSDataStruct; - -static const SiS300_LVDSDataStruct SiS300_CHTVUPALData[] = +static const SiS_LVDSDataStruct SiS300_CHTVUPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1048,7 +865,7 @@ { 936, 836, 936, 836} }; -static const SiS300_LVDSDataStruct SiS300_CHTVOPALData[] = +static const SiS_LVDSDataStruct SiS300_CHTVOPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1058,7 +875,7 @@ { 960, 750, 960, 750} }; -static const SiS300_LVDSDataStruct SiS300_CHTVSOPALData[] = +static const SiS_LVDSDataStruct SiS300_CHTVSOPALData[] = { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1068,13 +885,8 @@ { 944, 625, 944, 625} }; -typedef struct _SiS300_LVDSDesStruct -{ - USHORT LCDHDES; - USHORT LCDVDES; -} SiS300_LVDSDesStruct; -static const SiS300_LVDSDesStruct SiS300_PanelType00_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType00_1[] = { { 1059, 626 }, /* 2.08 */ { 1059, 624 }, @@ -1098,7 +910,7 @@ #endif }; -static const SiS300_LVDSDesStruct SiS300_PanelType01_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType01_1[] = { { 0, 0 }, /* 2.08 */ { 0, 0 }, @@ -1122,7 +934,7 @@ #endif }; -static const SiS300_LVDSDesStruct SiS300_PanelType02_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType02_1[] = { { 1059, 626 }, /* 2.08 */ { 1059, 624 }, @@ -1146,7 +958,7 @@ #endif }; -static const SiS300_LVDSDesStruct SiS300_PanelType03_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType03_1[] = { { 8, 436}, { 8, 440}, @@ -1159,7 +971,7 @@ {1343, 794} }; -static const SiS300_LVDSDesStruct SiS300_PanelType04_1[] = /* 1280x1024 */ +static const SiS_LVDSDesStruct SiS300_PanelType04_1[] = /* 1280x1024 */ { {1343, 798}, {1343, 794}, @@ -1172,7 +984,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType05_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType05_1[] = { {1343, 798}, {1343, 794}, @@ -1185,7 +997,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType06_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType06_1[] = /* Clevo Trumpion 1024x768 */ { {1343, 798}, {1343, 794}, @@ -1198,7 +1010,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType07_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType07_1[] = { {1343, 798}, {1343, 794}, @@ -1211,7 +1023,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType08_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType08_1[] = { {1059, 626}, {1059, 624}, @@ -1224,7 +1036,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType09_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType09_1[] = { {1343, 798}, {1343, 794}, @@ -1237,7 +1049,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0a_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0a_1[] = { {1059, 626}, {1059, 624}, @@ -1250,7 +1062,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0b_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0b_1[] = { {1343, 0}, {1343, 0}, @@ -1263,7 +1075,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0c_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0c_1[] = { {1343, 798}, {1343, 794}, @@ -1276,7 +1088,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0d_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0d_1[] = { {1343, 798}, {1343, 794}, @@ -1289,7 +1101,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0e_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0e_1[] = { {1343, 798}, {1343, 794}, @@ -1302,7 +1114,7 @@ { 0, 0} /* 1280x960 - not applicable */ }; -static const SiS300_LVDSDesStruct SiS300_PanelType0f_1[] = +static const SiS_LVDSDesStruct SiS300_PanelType0f_1[] = { {1343, 798}, {1343, 794}, @@ -1315,7 +1127,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType00_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType00_2[] = { {976, 527}, {976, 502}, @@ -1328,7 +1140,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType01_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType01_2[] = { {1152, 622}, {1152, 597}, @@ -1341,7 +1153,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType02_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType02_2[] = { {976, 527}, {976, 502}, @@ -1354,7 +1166,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType03_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType03_2[] = { {1152, 622}, {1152, 597}, @@ -1367,7 +1179,7 @@ {1152, 597} }; -static const SiS300_LVDSDesStruct SiS300_PanelType04_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType04_2[] = { {1152, 622}, {1152, 597}, @@ -1380,7 +1192,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType05_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType05_2[] = { {1152, 622}, {1152, 597}, @@ -1393,7 +1205,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType06_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType06_2[] = { {1152, 622}, {1152, 597}, @@ -1406,7 +1218,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType07_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType07_2[] = { {1152, 622}, {1152, 597}, @@ -1419,7 +1231,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType08_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType08_2[] = { {976, 527}, {976, 502}, @@ -1432,7 +1244,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType09_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType09_2[] = { {1152, 622}, {1152, 597}, @@ -1445,7 +1257,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0a_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0a_2[] = { {976, 527}, {976, 502}, @@ -1458,7 +1270,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0b_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0b_2[] = { { 1152, 700}, { 1152, 675}, @@ -1471,7 +1283,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0c_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0c_2[] = { {1152, 622}, {1152, 597}, @@ -1484,7 +1296,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0d_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0d_2[] = { {1152, 622}, {1152, 597}, @@ -1497,7 +1309,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0e_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0e_2[] = { {1152, 622}, {1152, 597}, @@ -1510,7 +1322,7 @@ { 0, 0} }; -static const SiS300_LVDSDesStruct SiS300_PanelType0f_2[] = +static const SiS_LVDSDesStruct SiS300_PanelType0f_2[] = { {1152, 622}, {1152, 597}, @@ -1523,8 +1335,36 @@ { 0, 0} }; +static const SiS_LVDSDesStruct SiS300_PanelTypeNS_1[]= +{ + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 805}, + { 0, 0}, + { 0, 0}, + { 0, 0} +}; + +static const SiS_LVDSDesStruct SiS300_PanelTypeNS_2[] = +{ + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0} +}; + /* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */ -static const SiS300_LVDSDesStruct SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ +static const SiS_LVDSDesStruct SiS300_PanelType04_1a[] = /* 1280x1024 (1366x1024) */ { {1330, 798}, /* 320x200 */ {1330, 794}, @@ -1537,7 +1377,7 @@ { 0, 0} /* 1360x1024 */ }; -static const SiS300_LVDSDesStruct SiS300_PanelType04_2a[] = +static const SiS_LVDSDesStruct SiS300_PanelType04_2a[] = { {1152, 622}, {1152, 597}, @@ -1551,7 +1391,7 @@ }; /* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */ -static const SiS300_LVDSDesStruct SiS300_PanelType04_1b[] = /* 1024x768 */ +static const SiS_LVDSDesStruct SiS300_PanelType04_1b[] = /* 1024x768 */ { {1330, 798}, /* 320x200 */ {1330, 794}, @@ -1562,7 +1402,7 @@ { 0, 805} /* 1024x768 / 512x384 */ }; -static const SiS300_LVDSDesStruct SiS300_PanelType04_2b[] = +static const SiS_LVDSDesStruct SiS300_PanelType04_2b[] = { {1152, 622}, {1152, 597}, @@ -1575,12 +1415,7 @@ /* CRT1 CRTC for slave modes */ -typedef struct _SiS300_LVDSCRT1DataStruct -{ -UCHAR CR[15]; -} SiS300_LVDSCRT1DataStruct; - -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1[] = { {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -1602,7 +1437,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_1_H[] = { {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x04, @@ -1624,7 +1459,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1[] = { {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, @@ -1649,7 +1484,7 @@ 0x01}} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_1_H[] = { {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x44, @@ -1698,7 +1533,7 @@ #endif }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1[] = { {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x01, @@ -1723,7 +1558,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_1_H[] = { {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x04, @@ -1748,7 +1583,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2[] = { {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, 0xf4,0x88,0x8f,0x73,0x20,0x00,0x06, @@ -1770,7 +1605,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1800x600_2_H[] = { {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e, 0xf4,0x88,0x8f,0x73,0x20,0x00,0x05, @@ -1792,7 +1627,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2[] = { {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, @@ -1817,7 +1652,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11024x768_2_H[] = { {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb, 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, @@ -1842,7 +1677,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2[] = { {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, 0x4a,0x80,0x8f,0x25,0x30,0x00,0x06, @@ -1867,7 +1702,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT11280x1024_2_H[] = { {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb, 0x4a,0x80,0x8f,0x25,0x30,0x00,0x01, @@ -1892,7 +1727,64 @@ 0x01}} }; -static const SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS300_LVDSCRT1XXXxXXX_1_H[] = +{ + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, + {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, + 0x01}}, + {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + + +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UNTSC[] = { {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, @@ -1914,7 +1806,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1ONTSC[] = { {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e, 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, @@ -1936,7 +1828,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1UPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -1958,7 +1850,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1OPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -1980,7 +1872,7 @@ 0x01 }} }; -static const SiS300_LVDSCRT1DataStruct SiS300_CHTVCRT1SOPAL[] = +static const SiS_LVDSCRT1DataStruct SiS300_CHTVCRT1SOPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -2002,12 +1894,7 @@ 0x01 }} }; -typedef struct _SiS300_CHTVRegDataStruct -{ - UCHAR Reg[16]; -} SiS300_CHTVRegDataStruct; - -static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = { {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, {{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, @@ -2017,7 +1904,7 @@ {{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 24: 800x600 NTSC 7/10 */ }; -static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = { {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, {{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}}, @@ -2027,7 +1914,7 @@ {{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}} /* Mode 23: 800x600 NTSC 3/4 */ }; -static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, @@ -2038,7 +1925,7 @@ }; -static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, @@ -2049,7 +1936,7 @@ }; -static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] = +static const SiS_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] = { {{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */ {{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}}, diff -urN linux-2.4.25/drivers/video/sis/310vtbl.h linux-2.4.26/drivers/video/sis/310vtbl.h --- linux-2.4.25/drivers/video/sis/310vtbl.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/310vtbl.h 2004-04-14 06:05:39.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -52,20 +49,7 @@ * */ -typedef struct _SiS310_StStruct -{ - UCHAR St_ModeID; - USHORT St_ModeFlag; - UCHAR St_StTableIndex; - UCHAR St_CRT2CRTC; - UCHAR St_ResInfo; - UCHAR VB_StTVFlickerIndex; - UCHAR VB_StTVEdgeIndex; - UCHAR VB_StTVYFilterIndex; - UCHAR St_PDC; -} SiS310_StStruct; - -static const SiS310_StStruct SiS310_SModeIDTable[]= +static const SiS_StStruct SiS310_SModeIDTable[]= { {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00, 0x40}, {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00, 0x40}, @@ -89,207 +73,184 @@ {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00, 0x40} }; -typedef struct _SiS310_ExtStruct +static const SiS_ExtStruct SiS310_EModeIDTable[]= { - UCHAR Ext_ModeID; - USHORT Ext_ModeFlag; - UCHAR Ext_ModeOffset; - USHORT Ext_VESAID; - UCHAR Ext_RESINFO; - UCHAR VB_ExtTVFlickerIndex; - UCHAR VB_ExtTVEdgeIndex; - UCHAR VB_ExtTVYFilterIndex; - UCHAR VB_ExtTVYFilterIndexROM661; - UCHAR REFindex; -} SiS310_ExtStruct; - -static const SiS310_ExtStruct SiS310_EModeIDTable[]= -{ - {0x6a,0x2212,0x04,0x0102,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x? */ - {0x2e,0x0a1b,0x03,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x8 */ - {0x2f,0x0a1b,0x03,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10}, /* 640x400x8 */ - {0x30,0x2a1b,0x04,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x8 */ - {0x31,0x0a1b,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x8 */ - {0x32,0x0a1b,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x8 */ - {0x33,0x0a1d,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x16 */ - {0x34,0x2a1d,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x16 */ - {0x35,0x0a1f,0x0a,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x32 */ - {0x36,0x2a1f,0x0a,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x32 */ - {0x37,0x0212,0x05,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x? */ - {0x38,0x0a1b,0x05,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x8 */ - {0x3a,0x0e3b,0x06,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */ - {0x3c,0x0e3b,0x07,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x8 */ - {0x3d,0x0e7d,0x07,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x16 */ - {0x40,0x9a1c,0x00,0x010d,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x15 */ - {0x41,0x9a1d,0x00,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x16 */ - {0x43,0x0a1c,0x03,0x0110,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, - {0x44,0x0a1d,0x03,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x16 */ - {0x46,0x2a1c,0x04,0x0113,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, - {0x47,0x2a1d,0x04,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x16 */ - {0x49,0x0a3c,0x05,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13}, - {0x4a,0x0a3d,0x05,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x16 */ - {0x4c,0x0e7c,0x06,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, - {0x4d,0x0e7d,0x06,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x16 */ - {0x50,0x9a1b,0x00,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x8 */ - {0x51,0xba1b,0x01,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x8 */ - {0x52,0xba1b,0x02,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x8 */ - {0x56,0x9a1d,0x00,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x16 */ - {0x57,0xba1d,0x01,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x16 */ - {0x58,0xba1d,0x02,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x16 */ - {0x59,0x9a1b,0x00,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x8 */ - {0x5a,0x021b,0x00,0x0138,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f}, /* 320x240x8 fstn */ - {0x5b,0x0a1d,0x00,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f}, /* 320x240x16 fstn */ - {0x5c,0xba1f,0x02,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x32 */ - {0x5d,0x0a1d,0x03,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10}, - {0x5e,0x0a1f,0x03,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10}, /* 640x400x32 */ - {0x62,0x0a3f,0x03,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x32 */ - {0x63,0x2a3f,0x04,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x32 */ - {0x64,0x0a7f,0x05,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x32 */ - {0x65,0x0eff,0x06,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x32 */ - {0x66,0x0eff,0x07,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x32 */ - {0x68,0x067b,0x08,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x8 */ - {0x69,0x06fd,0x08,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x16 */ - {0x6b,0x07ff,0x08,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x32 */ - {0x6c,0x067b,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x8 */ - {0x6d,0x06fd,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x16 */ - {0x6e,0x07ff,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x32 */ - {0x70,0x2a1b,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x8 */ - {0x71,0x0a1b,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x8 */ - {0x74,0x0a1d,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x16 */ - {0x75,0x0a3d,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x16 */ - {0x76,0x2a1f,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x32 */ - {0x77,0x0a1f,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x32 */ - {0x78,0x0a3f,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x32 */ - {0x79,0x0a3b,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x8 */ - {0x7a,0x2a1d,0x04,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x16 */ - {0x7c,0x0e3b,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x8 */ - {0x7d,0x0e7d,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x16 */ - {0x7e,0x0eff,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x32 */ - {0x23,0x0e3b,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x8 */ - {0x24,0x0e7d,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x16 */ - {0x25,0x0eff,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x32 */ - {0x26,0x0e3b,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x8 */ - {0x27,0x0e7d,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x16 */ - {0x28,0x0eff,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x32*/ - {0x29,0x0e1b,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, /* 1152x864 */ - {0x2a,0x0e3d,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, - {0x2b,0x0e7f,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, - {0x39,0x2a1b,0x0b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, /* 848x480 */ - {0x3b,0x2a3d,0x0b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, - {0x3e,0x2a7f,0x0b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, - {0x3f,0x2a1b,0x0b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, /* 856x480 */ - {0x42,0x2a3d,0x0b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, - {0x45,0x2a7f,0x0b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, - {0x48,0x2a1b,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, /* 1360x768 */ - {0x4b,0x2a3d,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, - {0x4e,0x2a7f,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, - {0x4f,0x9a1f,0x00,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x32 */ - {0x53,0x9a1f,0x00,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x32 */ - {0x54,0xba1f,0x01,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x32 */ - {0x5f,0x2a1b,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, /* 768x576x8 */ - {0x60,0x2a1d,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, /* 768x576x16 */ - {0x61,0x2a1f,0x0f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, /* 768x576x32 */ - {0xff,0x0000,0x00,0x0000,0, 0x00,0x00,0x00,0x00,0x00} -}; - -typedef struct _SiS310_Ext2Struct -{ - USHORT Ext_InfoFlag; - UCHAR Ext_CRT1CRTC; - UCHAR Ext_CRTVCLK; - UCHAR Ext_CRT2CRTC; - UCHAR ModeID; - USHORT XRes; - USHORT YRes; - UCHAR Ext_PDC; -} SiS310_Ext2Struct; - -static const SiS310_Ext2Struct SiS310_RefIndex[]= -{ - {0x085f,0x0d,0x03,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */ - {0x0067,0x0e,0x04,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */ - {0x0067,0x0f,0x08,0x48,0x6a, 800, 600, 0x40}, /* 0x2 */ - {0x0067,0x10,0x07,0x8b,0x6a, 800, 600, 0x40}, /* 0x3 */ - {0x0047,0x11,0x0a,0x00,0x6a, 800, 600, 0x40}, /* 0x4 */ - {0x0047,0x12,0x0d,0x00,0x6a, 800, 600, 0x40}, /* 0x5 */ - {0x0047,0x13,0x13,0x00,0x6a, 800, 600, 0x20}, /* 0x6 */ - {0x0107,0x14,0x1c,0x00,0x6a, 800, 600, 0x20}, /* 0x7 */ - {0xc85f,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */ - {0xc067,0x06,0x02,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */ - {0xc067,0x07,0x02,0x47,0x2e, 640, 480, 0x40}, /* 0xa */ - {0xc067,0x08,0x03,0x8a,0x2e, 640, 480, 0x40}, /* 0xb */ - {0xc047,0x09,0x05,0x00,0x2e, 640, 480, 0x40}, /* 0xc */ - {0xc047,0x0a,0x09,0x00,0x2e, 640, 480, 0x40}, /* 0xd */ - {0xc047,0x0b,0x0e,0x00,0x2e, 640, 480, 0x40}, /* 0xe */ - {0xc047,0x0c,0x15,0x00,0x2e, 640, 480, 0x40}, /* 0xf */ - {0x487f,0x04,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */ - {0xc04f,0x3c,0x01,0x06,0x31, 720, 480, 0x30}, /* 0x11 */ - {0x004f,0x3d,0x03,0x06,0x32, 720, 576, 0x30}, /* 0x12 */ - {0x0087,0x15,0x06,0x00,0x37,1024, 768, 0x30}, /* 0x13 */ - {0xc877,0x16,0x0b,0x06,0x37,1024, 768, 0x20}, /* 0x14 */ - {0xc067,0x17,0x0f,0x49,0x37,1024, 768, 0x20}, /* 0x15 */ - {0x0067,0x18,0x11,0x00,0x37,1024, 768, 0x20}, /* 0x16 */ - {0x0047,0x19,0x16,0x8c,0x37,1024, 768, 0x20}, /* 0x17 */ - {0x0107,0x1a,0x1b,0x00,0x37,1024, 768, 0x10}, /* 0x18 */ - {0x0107,0x1b,0x1f,0x00,0x37,1024, 768, 0x10}, /* 0x19 */ - {0x0087,0x1c,0x11,0x00,0x3a,1280,1024, 0x30}, /* 0x1a */ - {0x0137,0x1d,0x19,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */ - {0x0107,0x1e,0x1e,0x00,0x3a,1280,1024, 0x00}, /* 0x1c */ - {0x0207,0x1f,0x20,0x00,0x3a,1280,1024, 0x00}, /* 0x1d */ - {0x0227,0x20,0x21,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */ - {0x0407,0x21,0x22,0x00,0x3c,1600,1200, 0x00}, /* 0x1f */ - {0x0407,0x22,0x23,0x00,0x3c,1600,1200, 0x00}, /* 0x20 */ - {0x0407,0x23,0x25,0x00,0x3c,1600,1200, 0x00}, /* 0x21 */ - {0x0007,0x24,0x26,0x00,0x3c,1600,1200, 0x00}, /* 0x22 */ - {0x0007,0x25,0x2c,0x00,0x3c,1600,1200, 0x00}, /* 0x23 */ - {0x0007,0x26,0x34,0x00,0x3c,1600,1200, 0x00}, /* 0x24 */ - {0x407f,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */ - {0xc07f,0x01,0x00,0x04,0x50, 320, 240, 0x30}, /* 0x26 */ - {0x007f,0x02,0x04,0x05,0x51, 400, 300, 0x30}, /* 0x27 */ - {0xc077,0x03,0x0b,0x06,0x52, 512, 384, 0x30}, /* 0x28 */ - {0x8007,0x27,0x27,0x00,0x68,1920,1440, 0x00}, /* 0x29 */ - {0x4007,0x28,0x29,0x00,0x68,1920,1440, 0x00}, /* 0x2a */ - {0x4007,0x29,0x2e,0x00,0x68,1920,1440, 0x00}, /* 0x2b */ - {0x4007,0x2a,0x30,0x00,0x68,1920,1440, 0x00}, /* 0x2c */ - {0x4007,0x2b,0x35,0x00,0x68,1920,1440, 0x00}, /* 0x2d */ - {0x4005,0x2c,0x39,0x00,0x68,1920,1440, 0x00}, /* 0x2e */ - {0x4007,0x2d,0x2b,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */ - {0x4007,0x2e,0x31,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */ - {0x4007,0x2f,0x33,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */ - {0x4007,0x30,0x37,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */ - {0x4005,0x31,0x38,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */ - {0x0057,0x32,0x40,0x08,0x70, 800, 480, 0x30}, /* 0x34 */ - {0x0047,0x33,0x07,0x08,0x70, 800, 480, 0x30}, /* 0x35 */ - {0x0047,0x34,0x0a,0x08,0x70, 800, 480, 0x30}, /* 0x36 */ - {0x0057,0x35,0x0b,0x09,0x71,1024, 576, 0x30}, /* 0x37 */ - {0x0047,0x36,0x11,0x09,0x71,1024, 576, 0x30}, /* 0x38 */ - {0x0047,0x37,0x16,0x09,0x71,1024, 576, 0x30}, /* 0x39 */ - {0x0117,0x38,0x19,0x0a,0x75,1280, 720, 0x30}, /* 0x3a */ - {0x0107,0x39,0x1e,0x0a,0x75,1280, 720, 0x30}, /* 0x3b */ - {0x0207,0x3a,0x20,0x0a,0x75,1280, 720, 0x30}, /* 0x3c */ - {0x0127,0x3b,0x19,0x08,0x7c,1280, 960, 0x30}, /* 0x3d */ - {0x0227,0x4c,0x59,0x08,0x7c,1280, 960, 0x20}, /* 0x3e */ - {0xc07f,0x4e,0x00,0x06,0x5a, 320, 240, 0x30}, /* 0x3f */ /* FSTN 320x240 */ - {0x0077,0x42,0x5b,0x08,0x23,1280, 768, 0x30}, /* 0x40 */ /* TW: 0x5b was 0x12 */ - {0x0127,0x43,0x4d,0x08,0x26,1400,1050, 0x30}, /* 0x41 */ - {0x0207,0x4b,0x5a,0x08,0x26,1400,1050, 0x30}, /* 0x42 Non-BIOS, new */ - {0x0107,0x44,0x19,0x00,0x29,1152, 864, 0x30}, /* 0x43 Non-BIOS, new */ - {0x0107,0x4a,0x1e,0x00,0x29,1152, 864, 0x30}, /* 0x44 Non-BIOS, new */ - {0x0087,0x45,0x57,0x00,0x39, 848, 480, 0x30}, /* 0x45 848x480-38Hzi - Non-BIOS, new */ - {0xc067,0x46,0x55,0x0b,0x39, 848, 480, 0x30}, /* 0x46 848x480-60Hz - Non-BIOS, new */ - {0x0087,0x47,0x57,0x00,0x3f, 856, 480, 0x30}, /* 0x47 856x480-38Hzi - Non-BIOS, new */ - {0xc047,0x48,0x57,0x00,0x3f, 856, 480, 0x30}, /* 0x48 856x480-60Hz - Non-BIOS, new */ - {0x0067,0x49,0x58,0x0c,0x48,1360, 768, 0x30}, /* 0x49 1360x768-60Hz - Non-BIOS, new */ - {0x004f,0x4d,0x03,0x06,0x5f, 768, 576, 0x30}, /* 0x4a 768x576 */ - {0xffff,0x00,0x00,0x00,0x00, 0, 0, 0} + {0x6a,0x2212,0x0102,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x? */ + {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x8 */ + {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10}, /* 640x400x8 */ + {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x8 */ + {0x31,0x0a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x8 */ + {0x32,0x0a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x8 */ + {0x33,0x0a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x16 */ + {0x34,0x2a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x16 */ + {0x35,0x0a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11}, /* 720x480x32 */ + {0x36,0x2a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12}, /* 720x576x32 */ + {0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x? */ + {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x8 */ + {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */ + {0x3c,0x0e3b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x8 */ + {0x3d,0x0e7d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x16 */ + {0x40,0x9a1c,0x010d,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x15 */ + {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x16 */ + {0x43,0x0a1c,0x0110,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, + {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x16 */ + {0x46,0x2a1c,0x0113,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, + {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x16 */ + {0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13}, + {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x16 */ + {0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, + {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x16 */ + {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x8 */ + {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x8 */ + {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x8 */ + {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x16 */ + {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x16 */ + {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x16 */ + {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x8 */ + {0x5a,0x021b,0x0138,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f}, /* 320x240x8 fstn */ + {0x5b,0x0a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x00,0x00,0x3f}, /* 320x240x16 fstn */ + {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x28}, /* 512x384x32 */ + {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10}, + {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10}, /* 640x400x32 */ + {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08}, /* 640x480x32 */ + {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00}, /* 800x600x32 */ + {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x32 */ + {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x32 */ + {0x66,0x0eff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x32 */ + {0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x8 */ + {0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x16 */ + {0x6b,0x07ff,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x32 */ + {0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x8 */ + {0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x16 */ + {0x6e,0x07ff,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x32 */ + {0x70,0x2a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x8 */ + {0x71,0x0a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x8 */ + {0x74,0x0a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x16 */ + {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x16 */ + {0x76,0x2a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x32 */ + {0x77,0x0a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x32 */ + {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x32 */ + {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x8 */ + {0x7a,0x2a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x34}, /* 800x480x16 */ + {0x7c,0x0e3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x8 */ + {0x7d,0x0e7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x16 */ + {0x7e,0x0eff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x32 */ + {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x8 */ + {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x16 */ + {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x32 */ + {0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x8 */ + {0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x16 */ + {0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x32*/ + {0x29,0x0e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, /* 1152x864 */ + {0x2a,0x0e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, + {0x2b,0x0e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, + {0x39,0x2a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, /* 848x480 */ + {0x3b,0x2a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, + {0x3e,0x2a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x45}, + {0x3f,0x2a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, /* 856x480 */ + {0x42,0x2a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, + {0x45,0x2a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x47}, + {0x48,0x2a1b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, /* 1360x768 */ + {0x4b,0x2a3d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, + {0x4e,0x2a7f,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, + {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x25}, /* 320x200x32 */ + {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x26}, /* 320x240x32 */ + {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x27}, /* 400x300x32 */ + {0x5f,0x2a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, /* 768x576 */ + {0x60,0x2a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, + {0x61,0x2a1f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x4a}, + {0x14,0x0e1b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b}, /* 1280x800 */ + {0x15,0x0e3d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b}, + {0x16,0x0e7f,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b}, + {0x17,0x0e1b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c}, /* 1680x1050 */ + {0x18,0x0e3d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c}, + {0x19,0x0e7f,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c}, + {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00} +}; + +static const SiS_Ext2Struct SiS310_RefIndex[]= +{ + {0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */ + {0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */ + {0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40}, /* 0x2 */ + {0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40}, /* 0x3 */ + {0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x4 */ + {0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x5 */ + {0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x6 */ + {0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x7 */ + {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */ + {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */ + {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40}, /* 0xa */ + {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40}, /* 0xb */ + {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xc */ + {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xd */ + {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xe */ + {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xf */ + {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */ + {0xc04f,0x3c,0x01,0x06,0x00,0x31, 720, 480, 0x30}, /* 0x11 */ + {0x004f,0x3d,0x03,0x06,0x00,0x32, 720, 576, 0x30}, /* 0x12 */ + {0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30}, /* 0x13 */ + {0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20}, /* 0x14 */ + {0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20}, /* 0x15 */ + {0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20}, /* 0x16 */ + {0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20}, /* 0x17 */ + {0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x18 */ + {0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x19 */ + {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30}, /* 0x1a */ + {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */ + {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1c */ + {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1d */ + {0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */ + {0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x1f */ + {0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x20 */ + {0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x21 */ + {0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x22 */ + {0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x23 */ + {0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x24 */ + {0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */ + {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30}, /* 0x26 */ + {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30}, /* 0x27 */ + {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30}, /* 0x28 */ + {0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x29 */ + {0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2a */ + {0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2b */ + {0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2c */ + {0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2d */ + {0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2e */ + {0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */ + {0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */ + {0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */ + {0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */ + {0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */ + {0x0057,0x32,0x40,0x08,0x00,0x70, 800, 480, 0x30}, /* 0x34 */ + {0x0047,0x33,0x07,0x08,0x00,0x70, 800, 480, 0x30}, /* 0x35 */ + {0x0047,0x34,0x0a,0x08,0x00,0x70, 800, 480, 0x30}, /* 0x36 */ + {0x0057,0x35,0x0b,0x09,0x00,0x71,1024, 576, 0x30}, /* 0x37 */ + {0x0047,0x36,0x11,0x09,0x00,0x71,1024, 576, 0x30}, /* 0x38 */ + {0x0047,0x37,0x16,0x09,0x00,0x71,1024, 576, 0x30}, /* 0x39 */ + {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3a */ + {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3b */ + {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3c */ + {0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30}, /* 0x3d */ + {0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20}, /* 0x3e */ + {0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30}, /* 0x3f */ /* FSTN 320x240 */ + {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30}, /* 0x40 */ /* 0x5b was 0x12 */ + {0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x41 */ + {0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x42 1400x1050-75Hz */ + {0x0107,0x44,0x19,0x00,0x00,0x29,1152, 864, 0x30}, /* 0x43 1152x864-75Hz */ + {0x0107,0x4a,0x1e,0x00,0x00,0x29,1152, 864, 0x30}, /* 0x44 1152x864-85Hz */ + {0x0087,0x45,0x57,0x00,0x00,0x39, 848, 480, 0x30}, /* 0x45 848x480-38Hzi */ + {0xc067,0x46,0x55,0x0b,0x00,0x39, 848, 480, 0x30}, /* 0x46 848x480-60Hz */ + {0x0087,0x47,0x57,0x00,0x00,0x3f, 856, 480, 0x30}, /* 0x47 856x480-38Hzi */ + {0xc047,0x48,0x57,0x00,0x00,0x3f, 856, 480, 0x30}, /* 0x48 856x480-60Hz */ + {0x0067,0x49,0x58,0x0c,0x00,0x48,1360, 768, 0x30}, /* 0x49 1360x768-60Hz */ + {0x004f,0x4d,0x03,0x06,0x00,0x5f, 768, 576, 0x30}, /* 0x4a 768x576-56Hz */ + {0x0067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30}, /* 0x4b 1280x800-60Hz */ + {0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30}, /* 0x4c 1680x1050-60Hz */ + {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0} }; -typedef struct _SiS310_CRT1TableStruct -{ - UCHAR CR[17]; -} SiS310_CRT1TableStruct; - -static const SiS310_CRT1TableStruct SiS310_CRT1Table[]= +static const SiS_CRT1TableStruct SiS310_CRT1Table[]= { {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f, 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00, @@ -310,7 +271,7 @@ {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e, 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05, 0x00}}, /* 0x5 */ -#endif +#endif {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, /* 0x05 - corrected 640x480-60 */ 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, 0x00}}, @@ -329,16 +290,16 @@ 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, 0x00}}, /* 0x8 */ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f, - 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, /* TW: Corrected VBE */ + 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05, /* Corrected VBE */ 0x61}}, /* 0x9 */ {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e, 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05, 0x61}}, /* 0xa */ {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e, - 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, /* TW: Corrected VBE */ + 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05, /* Corrected VBE */ 0x61}}, /* 0xb */ {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f, - 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* TW: Corrected VDE, VBE */ + 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01, /* Corrected VDE, VBE */ 0x00}}, /* 0xc */ {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0, 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05, @@ -466,7 +427,7 @@ {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1, 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02, 0x01}}, /* 0x36 */ - {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* TW: 95 was 15 - illegal HBE! */ + {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1, /* 95 was 15 - illegal HBE! */ 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02, 0x01}}, /* 0x37 */ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4, @@ -498,7 +459,7 @@ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e, 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02, 0x00}}, /* 0x3f */ - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, /* TW: The following from 650/LVDS BIOS */ + {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1, 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02, 0x01}}, /* 0x40 */ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, @@ -510,31 +471,31 @@ {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10, 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03, 0x00}}, /* 0x43 */ - {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* New, 1152x864-75, not in BIOS */ + {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */ 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07, 0x01}}, /* 0x44 */ - {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* New, 848x480-38i, not in BIOS */ + {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */ 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, 0x00}}, /* 0x45 */ - {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* New, 848x480-60, not in BIOS */ + {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */ 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06, 0x00}}, /* 0x46 */ - {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* New, 856x480-38i, not in BIOS */ + {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */ 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02, 0x00}}, /* 0x47 */ - {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* New, 856x480-60, not in BIOS */ + {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */ 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02, 0x00}}, /* 0x48 */ - {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* New, 1360x768-60, not in BIOS */ + {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */ 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03, 0x01}}, /* 0x49 */ - {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* New, 1152x864-84, not in any BIOS */ + {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84 */ 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03, 0x01}}, /* 0x4a */ - {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* New, 1400x1050-75, not in any BIOS */ + {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* 1400x1050-75 */ 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03, 0x00}}, /* 0x4b */ - {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* New, 1280x960-85, not in any BIOS */ + {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */ 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07, 0x01}}, /* 0x4c */ {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */ @@ -542,16 +503,16 @@ 0x01}}, /* 0x4d */ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* FSTN 320x480, TEMP - possibly invalid */ 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00, - 0x00}} /* 0x4e */ + 0x00}}, /* 0x4e */ + {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */ + 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07, + 0x21}}, /* 0x4f */ + {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, /* 1680x1050-60 */ + 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c, + 0x20}} /* 0x50 */ }; -typedef struct _SiS310_MCLKDataStruct -{ - UCHAR SR28,SR29,SR2A; - USHORT CLOCK; -} SiS310_MCLKDataStruct; - -static const SiS310_MCLKDataStruct SiS310_MCLKData_0_315[] = +static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] = { { 0x3b,0x22,0x01,143}, { 0x5c,0x23,0x01,166}, @@ -563,7 +524,7 @@ { 0x5c,0x23,0x01,166} }; -static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] = +static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] = { { 0x5a,0x64,0x82, 66}, { 0xb3,0x45,0x82, 83}, @@ -575,7 +536,7 @@ { 0x37,0x22,0x82,133} }; -static const SiS310_MCLKDataStruct SiS310_MCLKData_0_330[] = +static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] = { { 0x5c,0x23,0x01,166}, { 0x5c,0x23,0x01,166}, @@ -587,7 +548,7 @@ { 0x79,0x06,0x01,250} }; -static const SiS310_MCLKDataStruct SiS310_MCLKData_0_660[] = /* TODO */ +static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] = { { 0x5c,0x23,0x82,166}, { 0x5c,0x23,0x82,166}, @@ -599,7 +560,19 @@ { 0x37,0x21,0x82,200} }; -static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] = +static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] = +{ + { 0x37,0x22,0x82,133}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x7c,0x08,0x82,200}, + { 0x29,0x21,0x82,150}, + { 0x5c,0x23,0x82,166}, + { 0x65,0x23,0x82,183}, + { 0x37,0x21,0x82,200} +}; + +static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */ { { 0x29,0x21,0x82,150}, { 0x5c,0x23,0x82,166}, @@ -611,13 +584,7 @@ { 0x37,0x22,0x82,133} }; -typedef struct _SiS310_VCLKDataStruct -{ - UCHAR SR2B,SR2C; - USHORT CLOCK; -} SiS310_VCLKDataStruct; - -static const SiS310_VCLKDataStruct SiS310_VCLKData[]= +static SiS_VCLKDataStruct SiS310_VCLKData[]= { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -630,7 +597,7 @@ { 0x53,0xe2, 50}, /* 0x08 */ { 0x74,0x67, 52}, /* 0x09 */ { 0x6d,0x66, 56}, /* 0x0a */ - { 0x5a,0x64, 65}, /* 0x0b */ /* TW: was 6c c3 - WRONG */ + { 0x5a,0x64, 65}, /* 0x0b */ /* was 6c c3 - WRONG */ { 0x46,0x44, 67}, /* 0x0c */ { 0xb1,0x46, 68}, /* 0x0d */ { 0xd3,0x4a, 72}, /* 0x0e */ @@ -644,7 +611,7 @@ { 0x62,0x44, 94}, /* 0x16 */ { 0x2b,0x41,104}, /* 0x17 */ { 0x3a,0x23,105}, /* 0x18 */ - { 0x70,0x44,108}, /* 0x19 */ + { 0x70,0x44,108}, /* 0x19 */ { 0x3c,0x23,109}, /* 0x1a */ { 0x5e,0x43,113}, /* 0x1b */ { 0xbc,0x44,116}, /* 0x1c */ @@ -677,49 +644,51 @@ { 0xea,0x08,340}, /* 0x37 */ { 0xe8,0x07,376}, /* 0x38 */ { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a */ /* 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b */ /* 301 TV */ - { 0x62,0x24, 70}, /* 0x3c */ /* 301 TV */ - { 0x62,0x64, 70}, /* 0x3d */ /* 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e */ /* 301 TV */ - { 0x20,0x26, 33}, /* 0x3f */ /* 301 TV */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ { 0x31,0xc2, 39}, /* 0x40 */ - { 0x60,0x36, 30}, /* 0x41 */ /* Chrontel */ - { 0x40,0x4a, 28}, /* 0x42 */ /* Chrontel */ - { 0x9f,0x46, 44}, /* 0x43 */ /* Chrontel */ + { 0x60,0x36, 30}, /* 0x41 Chrontel */ + { 0x40,0x4a, 28}, /* 0x42 Chrontel */ + { 0x9f,0x46, 44}, /* 0x43 Chrontel */ { 0x97,0x2c, 26}, /* 0x44 */ - { 0x44,0xe4, 25}, /* 0x45 */ /* Chrontel */ - { 0x7e,0x32, 47}, /* 0x46 */ /* Chrontel */ - { 0x8a,0x24, 31}, /* 0x47 */ /* Chrontel */ - { 0x97,0x2c, 26}, /* 0x48 */ /* Chrontel */ + { 0x44,0xe4, 25}, /* 0x45 Chrontel */ + { 0x7e,0x32, 47}, /* 0x46 Chrontel */ + { 0x8a,0x24, 31}, /* 0x47 Chrontel */ + { 0x97,0x2c, 26}, /* 0x48 Chrontel */ { 0xce,0x3c, 39}, /* 0x49 */ - { 0x52,0x4a, 36}, /* 0x4a */ /* Chrontel */ + { 0x52,0x4a, 36}, /* 0x4a Chrontel */ { 0x34,0x61, 95}, /* 0x4b */ { 0x78,0x27,108}, /* 0x4c - was 102 */ - { 0x66,0x43,123}, /* 0x4d */ /* Modes 0x26-0x28 (1400x1050) */ + { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ { 0x41,0x4e, 21}, /* 0x4e */ - { 0xa1,0x4a, 29}, /* 0x4f */ /* Chrontel */ + { 0xa1,0x4a, 29}, /* 0x4f Chrontel */ { 0x19,0x42, 42}, /* 0x50 */ - { 0x54,0x46, 58}, /* 0x51 */ /* Chrontel */ + { 0x54,0x46, 58}, /* 0x51 Chrontel */ { 0x25,0x42, 61}, /* 0x52 */ - { 0x44,0x44, 66}, /* 0x53 */ /* Chrontel */ - { 0x3a,0x62, 70}, /* 0x54 */ /* Chrontel */ - { 0x62,0xc6, 34}, /* 0x55 - added for 848x480-60 (not in any BIOS) */ - { 0x6a,0xc6, 37}, /* 0x56 - added for 848x480-75 (not in any BIOS) - TEMP */ - { 0xbf,0xc8, 35}, /* 0x57 - added for 856x480-38i,60 (not in any BIOS) */ - { 0x30,0x23, 88}, /* 0x58 - added for 1360x768-62 (is 60Hz!) (not in any BIOS) */ - { 0x52,0x07,149}, /* 0x59 - added for 1280x960-85 (Not in any BIOS) */ - { 0x56,0x07,156}, /* 0x5a - added for 1400x1050-75 */ - { 0x70,0x29, 81} /* 0x5b - added for 1280x768 LCD */ -}; - -typedef struct _SiS310_VBVCLKDataStruct -{ - UCHAR Part4_A,Part4_B; - USHORT CLOCK; -} SiS310_VBVCLKDataStruct; + { 0x44,0x44, 66}, /* 0x53 Chrontel */ + { 0x3a,0x62, 70}, /* 0x54 Chrontel */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x45,0x25, 83}, /* 0x5c 1280x800 */ + { 0x70,0x0a,147}, /* 0x5d 1680x1050 */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 */ + { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */ + { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x5a,0x64, 65} /* 0x63 1280x720 (LCD LVDS) */ +}; -static const SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]= +static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]= { { 0x1b,0xe1, 25}, /* 0x00 */ { 0x4e,0xe4, 28}, /* 0x01 */ @@ -732,7 +701,7 @@ { 0x53,0x47, 50}, /* 0x08 */ { 0x74,0x67, 52}, /* 0x09 */ { 0x6d,0x66, 56}, /* 0x0a */ - { 0x35,0x62, 65}, /* 0x0b */ /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62 */ + { 0x35,0x62, 65}, /* 0x0b */ /* Was 0x5a,0x64 - 650/LVDS+301: 35,62 */ { 0x46,0x44, 67}, /* 0x0c */ { 0xb1,0x46, 68}, /* 0x0d */ { 0xd3,0x4a, 72}, /* 0x0e */ @@ -785,47 +754,48 @@ { 0xea,0x08,340}, /* 0x37 */ { 0xe8,0x07,376}, /* 0x38 */ { 0xde,0x06,389}, /* 0x39 */ - { 0x52,0x2a, 54}, /* 0x3a */ /* 301 TV */ - { 0x52,0x6a, 27}, /* 0x3b */ /* 301 TV */ - { 0x62,0x24, 70}, /* 0x3c */ /* 301 TV */ - { 0x62,0x64, 70}, /* 0x3d */ /* 301 TV */ - { 0xa8,0x4c, 30}, /* 0x3e */ /* 301 TV */ - { 0x20,0x26, 33}, /* 0x3f */ /* 301 TV */ + { 0x52,0x2a, 54}, /* 0x3a 301 TV - start */ + { 0x52,0x6a, 27}, /* 0x3b 301 TV */ + { 0x62,0x24, 70}, /* 0x3c 301 TV */ + { 0x62,0x64, 70}, /* 0x3d 301 TV */ + { 0xa8,0x4c, 30}, /* 0x3e 301 TV */ + { 0x20,0x26, 33}, /* 0x3f 301 TV */ { 0x31,0xc2, 39}, /* 0x40 */ - { 0x2e,0x48, 25}, /* 0x41 */ /* Replacement for LCD on 315 for index 0 */ - { 0x24,0x46, 25}, /* 0x42 */ /* Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */ - { 0x26,0x64, 28}, /* 0x43 */ /* Replacement for LCD on 315 for index 1 */ - { 0x37,0x64, 40}, /* 0x44 */ /* Replacement for LCD on 315 for index 4 */ - { 0xa1,0x42,108}, /* 0x45 */ /* 1280x960 LCD */ - { 0x37,0x61,100}, /* 0x46 */ /* 1280x960 LCD */ + { 0x2e,0x48, 25}, /* 0x41 Replacement for LCD on 315 for index 0 */ + { 0x24,0x46, 25}, /* 0x42 Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */ + { 0x26,0x64, 28}, /* 0x43 Replacement for LCD on 315 for index 1 */ + { 0x37,0x64, 40}, /* 0x44 Replacement for LCD on 315 for index 4 */ + { 0xa1,0x42,108}, /* 0x45 1280x960 LCD */ + { 0x37,0x61,100}, /* 0x46 1280x960 LCD */ { 0x78,0x27,108}, /* 0x47 */ - { 0x97,0x2c, 26}, /* 0x48 */ /* UNUSED - Entries from here new, not in any BIOS */ - { 0xce,0x3c, 39}, /* 0x49 */ /* UNUSED */ - { 0x52,0x4a, 36}, /* 0x4a */ /* UNUSED */ - { 0x34,0x61, 95}, /* 0x4b */ /* UNUSED */ - { 0x78,0x27,108}, /* 0x4c */ /* UNUSED */ - { 0x66,0x43,123}, /* 0x4d */ /* 1400x1050-60 */ - { 0x41,0x4e, 21}, /* 0x4e */ /* UNUSED */ - { 0xa1,0x4a, 29}, /* 0x4f */ /* UNUSED */ - { 0x19,0x42, 42}, /* 0x50 */ /* UNUSED */ - { 0x54,0x46, 58}, /* 0x51 */ /* UNUSED */ - { 0x25,0x42, 61}, /* 0x52 */ /* UNUSED */ - { 0x44,0x44, 66}, /* 0x53 */ /* UNUSED */ - { 0x3a,0x62, 70}, /* 0x54 */ /* UNUSED */ - { 0x62,0xc6, 34}, /* 0x55 */ /* 848x480-60 */ - { 0x6a,0xc6, 37}, /* 0x56 */ /* 848x480-75 - TEMP, UNUSED */ - { 0xbf,0xc8, 35}, /* 0x57 */ /* 856x480-38i,60 */ - { 0x30,0x23, 88}, /* 0x58 */ /* 1360x768-62 (is 60Hz!) TEMP, UNUSED */ - { 0x52,0x07,149}, /* 0x59 */ /* 1280x960-85 */ - { 0x56,0x07,156}, /* 0x5a */ /* 1400x1050-75 */ - { 0x70,0x29, 81} /* 0x5b */ /* 1280x768 LCD */ -}; - -static const UCHAR SiS310_ScreenOffset[] = -{ - 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64, - 0x78,0x80,0x2d,0x35,0x57,0x48,0x55,0x30, - 0xff + { 0x97,0x2c, 26}, /* 0x48 UNUSED */ + { 0xce,0x3c, 39}, /* 0x49 UNUSED */ + { 0x52,0x4a, 36}, /* 0x4a UNUSED */ + { 0x34,0x61, 95}, /* 0x4b UNUSED */ + { 0x78,0x27,108}, /* 0x4c UNUSED */ + { 0x66,0x43,123}, /* 0x4d 1400x1050-60 */ + { 0x41,0x4e, 21}, /* 0x4e UNUSED */ + { 0xa1,0x4a, 29}, /* 0x4f UNUSED */ + { 0x19,0x42, 42}, /* 0x50 UNUSED */ + { 0x54,0x46, 58}, /* 0x51 UNUSED */ + { 0x25,0x42, 61}, /* 0x52 UNUSED */ + { 0x44,0x44, 66}, /* 0x53 UNUSED */ + { 0x3a,0x62, 70}, /* 0x54 UNUSED */ + { 0x62,0xc6, 34}, /* 0x55 848x480-60 */ + { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP, UNUSED */ + { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */ + { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */ + { 0x52,0x07,149}, /* 0x59 1280x960-85 */ + { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */ + { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */ + { 0x9c,0x62, 69}, /* 0x5c 1280x800 LCD - wrong? */ + { 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */ + { 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */ + { 0x52,0x27, 75}, /* 0x5f 1280x720 LCD TMDS + HDTV (correct) */ + { 0x63,0x46, 68}, /* 0x60 1280x768_2 */ + { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */ + { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ + { 0x5a,0x64, 65} /* 0x63 1280x720 (LCD LVDS) */ }; static const DRAM4Type SiS310_SR15[8] = { @@ -873,12 +843,7 @@ static const USHORT SiS310_YCSenseData2 = 0x016b; #endif -typedef struct _SiS310_PanelDelayTblStruct -{ - UCHAR timer[2]; -} SiS310_PanelDelayTblStruct; - -static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]= +static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]= { {{0x10,0x40}}, {{0x10,0x40}}, @@ -898,7 +863,7 @@ {{0x10,0x40}} }; -static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]= +static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]= { {{0x28,0xc8}}, {{0x28,0xc8}}, @@ -922,28 +887,18 @@ /* SIS VIDEO BRIDGE ----------------------------------------- */ /**************************************************************/ -typedef struct _SiS310_LCDDataStruct -{ - USHORT RVBHCMAX; - USHORT RVBHCFACT; - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS310_LCDDataStruct; - -static const SiS310_LCDDataStruct SiS310_StLCD1024x768Data[]= +static const SiS_LCDDataStruct SiS310_St2LCD1024x768Data[] = { { 62, 25, 800, 546,1344, 806}, { 32, 15, 930, 546,1344, 806}, - { 32, 15, 930, 546,1344, 806}, + { 62, 25, 800, 546,1344, 806}, { 104, 45, 945, 496,1344, 806}, { 62, 25, 800, 546,1344, 806}, { 31, 18,1008, 624,1344, 806}, { 1, 1,1344, 806,1344, 806} }; -static const SiS310_LCDDataStruct SiS310_ExtLCD1024x768Data[] = +static const SiS_LCDDataStruct SiS310_ExtLCD1024x768Data[] = { { 42, 25,1536, 419,1344, 806}, { 48, 25,1536, 369,1344, 806}, @@ -951,28 +906,10 @@ { 48, 25,1536, 369,1344, 806}, { 12, 5, 896, 500,1344, 806}, { 42, 25,1024, 625,1344, 806}, - { 1, 1,1344, 806,1344, 806}, - { 12, 5, 896, 500,1344, 806}, - { 42, 25,1024, 625,1344, 806}, - { 1, 1,1344, 806,1344, 806}, - { 12, 5, 896, 500,1344, 806}, - { 42, 25,1024, 625,1344, 806}, - { 1, 1,1344, 806,1344, 806} - -}; - -static const SiS310_LCDDataStruct SiS310_St2LCD1024x768Data[] = -{ - { 62, 25, 800, 546,1344, 806}, - { 32, 15, 930, 546,1344, 806}, - { 62, 25, 800, 546,1344, 806}, - { 104, 45, 945, 496,1344, 806}, - { 62, 25, 800, 546,1344, 806}, - { 31, 18,1008, 624,1344, 806}, { 1, 1,1344, 806,1344, 806} }; -static const SiS310_LCDDataStruct SiS310_StLCD1280x1024Data[] = +static const SiS_LCDDataStruct SiS310_St2LCD1280x1024Data[] = { { 22, 5, 800, 510,1650,1088}, { 22, 5, 800, 510,1650,1088}, @@ -984,7 +921,7 @@ { 1, 1,1688,1066,1688,1066} }; -static const SiS310_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = +static const SiS_LCDDataStruct SiS310_ExtLCD1280x1024Data[] = { { 211, 60,1024, 501,1688,1066}, { 211, 60,1024, 508,1688,1066}, @@ -993,53 +930,10 @@ { 211, 60,1024, 500,1688,1066}, { 211, 75,1024, 625,1688,1066}, { 211, 120,1280, 798,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1800,1000,1688,1066} /* 1280x960 - does not work, use panel scaler instead */ -}; - -static const SiS310_LCDDataStruct SiS310_St2LCD1280x1024Data[] = -{ - { 22, 5, 800, 510,1650,1088}, - { 22, 5, 800, 510,1650,1088}, - { 176, 45, 900, 510,1650,1088}, - { 176, 45, 900, 510,1650,1088}, - { 22, 5, 800, 510,1650,1088}, - { 13, 5,1024, 675,1560,1152}, - { 16, 9,1266, 804,1688,1072}, { 1, 1,1688,1066,1688,1066} }; -static const SiS310_LCDDataStruct SiS310_NoScaleData1024x768[] = -{ - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1344, 806,1344, 806}, /* 640x400 - does not work */ - { 1, 1,1344, 806,1344, 806}, /* 640x480 - does not work */ - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1344, 806,1344, 806}, - { 1, 1,1344, 806,1344, 806} -}; - -static const SiS310_LCDDataStruct SiS310_NoScaleData1280x1024[] = -{ - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066}, - { 1, 1,1688,1066,1688,1066} -}; - -typedef struct _SiS310_Part2PortTblStruct -{ - UCHAR CR[12]; -} SiS310_Part2PortTblStruct; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] = +static const SiS_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] = { {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, @@ -1047,646 +941,37 @@ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} + {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} }; -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] = -{ - {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}}, - {{0x2c,0x12,0x38,0x55,0x2f,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}}, - {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}}, - {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}}, - {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}}, - {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}}, - {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, /* others */ -/* 0x36,0x13,0x02,0x25,0xff,0x03,0x45,0x09,0x07,0xf9,0x00,0x24 my */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; +/* *** LCDA *** */ -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] = -{ -#if 1 /* Data from 650/301LVx 1.10.6s and others */ - {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x25,0x13,0xc9,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}} +#if 0 +static const SiS_LVDSDataStruct SiS_LCDA1600x1200Data_1[]= +{ /* Clevo, 651+301C */ + {1200, 450, 2048,1250}, + {1200, 400, 2048,1250}, + {1280, 450, 2048,1250}, + {1280, 400, 2048,1250}, + {1200, 530, 2048,1250}, + {1360, 650, 2048,1250}, + {1584, 818, 2048,1250}, + {1688,1066, 2048,1250}, + {1688,1066, 2048,1250}, +#if 0 + {2048,1250, 2048,1250} /* this should be correct */ #endif -#if 0 /* Data from my 301LV */ - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, /* TEST */ - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}, - {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}} +#if 1 + {2160,1250, 2048,1250} /* ? */ #endif }; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_1[] = -{ /* Acer; BIOS data invalid, last row taken from _3 */ - {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}}, - {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}}, - {{0x36,0x13,0x02,0x25,0xFF,0x03,0x45,0x09,0x07,0xF9,0x00,0x24}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_2[] = -{ /* Acer */ - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} -}; - -/* 1 2 4 5 6 1c 1d 1f 20 21 23 25 */ -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_3[] = -{ /* Acer */ - {{0x31,0x1B,0xC4,0xDA,0xB0,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x34,0x1B,0x9F,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x3E,0x1B,0xCF,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_1[] = -{ - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_2[] = -{ - {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}}, - {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}}, - {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}}, - {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}}, - {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}}, - {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}}, - {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}}, - {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_3[] = -{ - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}, - {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] = -{ - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] = -{ - {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x3A,0x1B,0x54,0x7A,0x48,0x80,0x24,0x52,0x30,0xA3,0x3A,0x02}}, - {{0x36,0x1B,0x90,0xB6,0x84,0xA8,0x24,0x7A,0x30,0xCB,0x62,0x02}}, - {{0x3A,0x1C,0xE4,0x0A,0xD8,0xE0,0x24,0xB2,0x30,0x03,0x9A,0x02}}, - {{0x4A,0x24,0x64,0x8A,0x58,0x20,0x34,0xF2,0x30,0x43,0xDA,0x52}}, - {{0x47,0x24,0x71,0x97,0x65,0x3E,0x34,0x10,0x40,0x61,0xF8,0x02}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}} -}; - -static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] = -{ - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}, - {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}} -}; - -/* CRT1 CRTC for LCDA */ - -typedef struct _SiS310_LCDACRT1DataStruct -{ - UCHAR CR[17]; -}SiS310_LCDACRT1DataStruct; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1[]= -{ - {{0x73,0x4f,0x4f,0x97,0x59,0x84,0xb4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x82,0x1f, - 0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x59,0x84,0xb4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x82,0x1f, - 0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x04,0x3e, - 0xE2,0x89,0xdf,0xdf,0x05,0x00,0x00,0x05, - 0x00}}, - {{0x87,0x63,0x63,0x8B,0x6D,0x18,0x7c,0xf0, - 0x5A,0x81,0x57,0x57,0x7D,0x00,0x00,0x06, - 0x01}}, - {{0xA3,0x7f,0x7f,0x87,0x89,0x94,0x24,0xf5, - 0x02,0x89,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_1_H[]= -{ - {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0xb4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x82,0x1f, - 0x60,0x87,0x5D,0x5D,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0xb4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x82,0x1f, - 0x60,0x87,0x5D,0x5D,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x04,0x3e, - 0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05, - 0x00}}, - {{0x55,0x31,0x31,0x99,0x3b,0x06,0x7c,0xf0, - 0x5A,0x81,0x57,0x57,0x7D,0x00,0x00,0x01, - 0x01}}, - {{0x63,0x3F,0x3F,0x87,0x49,0x94,0x24,0xF5, - 0x02,0x89,0xFF,0xFF,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2[]= -{ - {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb, - 0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb, - 0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb, - 0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb, - 0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x06, - 0x01}}, - {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xb3, - 0x72,0x89,0xdf,0x03,0x02,0x30,0x00,0x06, - 0x01}}, - {{0xa3,0x63,0x63,0x98,0x78,0x19,0x24,0xf1, - 0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x02, - 0x01}}, - {{0xa3,0x7f,0x7f,0x87,0x89,0x94,0x24,0xf5, - 0x02,0x89,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11024x768_2_H[]= -{ - {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb, - 0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb, - 0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb, - 0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb, - 0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xb3, - 0x72,0x89,0xdf,0x03,0x02,0x30,0x00,0x01, - 0x01 }}, - {{0x71,0x31,0x31,0x98,0x46,0x17,0x24,0xf1, - 0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x02, - 0x01 }}, - {{0x63,0x3f,0x3f,0x87,0x4c,0x97,0x24,0xf5, - 0x0f,0x86,0xff,0xff,0x25,0x30,0x00,0x01, - 0x01 }} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1[]= -{ /* Acer */ - {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x08,0x3e, - 0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06, - 0x00}}, - {{0x92,0x63,0x63,0x96,0x6c,0x18,0x80,0xf0, - 0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06, - 0x01}}, - {{0xae,0x7f,0x7f,0x92,0x88,0x94,0x28,0xf5, - 0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_1_H[]= -{ /* Acer */ - {{0x56,0x27,0x27,0x9a,0x31,0x1c,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x27,0x9a,0x31,0x1c,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x05, - 0x01}}, - {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x08,0x3e, - 0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05, - 0x00}}, - {{0x60,0x31,0x31,0x84,0x3a,0x86,0x80,0xf0, - 0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01, - 0x01}}, - {{0x6e,0x3f,0x3f,0x92,0x48,0x94,0x28,0xf5, - 0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2[]= -{ /* Illegal data in BIOS (Acer, Compaq) */ - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11280x1024_2_H[]= -{ /* Illegal data in BIOS (Acer, Compaq) */ - {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb, - 0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x4f,0x31,0x31,0x93,0x3e,0x86,0x24,0xf1, - 0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01, - 0x01 }}, - {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01, - 0x01 }} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11400x1050_1[]= -{ - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f, - 0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f, - 0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0xee,0x1f, - 0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x83,0x63,0x63,0x87,0x68,0x16,0x66,0xf0, - 0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x06, - 0x01}}, - {{0x9f,0x7f,0x7f,0x83,0x84,0x92,0x0e,0xf5, - 0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x02, - 0x01}}, - {{0xbf,0x9f,0x9f,0x83,0xa4,0x12,0x0e,0x5a, - 0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x07, - 0x01}}, - {{0xce,0xae,0xae,0x92,0xb3,0x01,0x28,0x10, - 0x1a,0x80,0x19,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11400x1050_1_H[]= -{ - {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, - 0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x27,0x8b,0x30,0x1e,0x9e,0x1f, - 0x92,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f, - 0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05, - 0x00}}, - {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0xee,0x1f, - 0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05, - 0x00}}, - {{0x51,0x31,0x31,0x95,0x36,0x04,0x66,0xf0, - 0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x01, - 0x01}}, - {{0x5f,0x3f,0x3f,0x83,0x44,0x92,0x0e,0xf5, - 0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x01, - 0x01}}, - {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x0e,0x5a, - 0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x05, - 0x01}}, - {{0x76,0x56,0x56,0x9a,0x5b,0x89,0x28,0x10, - 0x1c,0x80,0x19,0x19,0x29,0x0b,0x00,0x05, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11400x1050_2[]= -{ - {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03, - 0x01}}, - {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a, - 0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03, - 0x00}}, - {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9e, - 0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x03, - 0x00}}, - {{0xce,0x63,0x63,0x92,0x96,0x04,0x28,0xd4, - 0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x07, - 0x01}}, - {{0xce,0x7f,0x7f,0x92,0xa4,0x12,0x28,0xd4, - 0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x9f,0x92,0xb4,0x02,0x28,0x5a, - 0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x03, - 0x01}}, - {{0xce,0xae,0xae,0x92,0xbc,0x0a,0x28,0x10, - 0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x03, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11400x1050_2_H[]= -{ - {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a, - 0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06, - 0x00}}, - {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9e, - 0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x06, - 0x00}}, - {{0x9c,0x31,0x31,0x80,0x64,0x92,0x28,0xd4, - 0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x06, - 0x01}}, - {{0x8e,0x3f,0x3f,0x92,0x64,0x12,0x28,0xd4, - 0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x06, - 0x01}}, - {{0x7e,0x4f,0x4f,0x82,0x64,0x12,0x28,0x5a, - 0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x06, - 0x01}}, - {{0x76,0x56,0x56,0x9a,0x64,0x92,0x28,0x10, - 0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x05, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11600x1200_1[]= -{ - {{0x83,0x4F,0x4F,0x87,0x51,0x09,0xC0,0x1F, - 0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x8E,0x1F, - 0x5E,0x82,0x5D,0x5D,0x8F,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x4F,0x87,0x51,0x09,0xC0,0x1F, - 0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x8E,0x1F, - 0x5E,0x82,0x5D,0x5D,0x8F,0x10,0x00,0x06, - 0x00}}, - {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x10,0x3E, - 0xE0,0x84,0xDF,0xDF,0x11,0x00,0x00,0x06, - 0x00}}, - {{0x97,0x63,0x63,0x9B,0x65,0x1D,0x88,0xF0, - 0x58,0x8C,0x57,0x57,0x89,0x20,0x00,0x06, - 0x01}}, - {{0xB3,0x7F,0x7F,0x97,0x81,0x99,0x30,0xF5, - 0x00,0x84,0xFF,0xFF,0x31,0x10,0x00,0x02, - 0x01}}, - {{0xD3,0x9F,0x9F,0x97,0xA1,0x19,0x30,0x5A, - 0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x07, - 0x01}}, - {{0xE2,0xAE,0xAE,0x86,0xB0,0x88,0x4A,0x10, - 0x1A,0x8E,0x19,0x19,0x4B,0x2F,0x00,0x03, - 0x00}}, - {{0xFB,0xC7,0xC7,0x9F,0xC9,0x81,0xE0,0x10, - 0xB0,0x84,0xAF,0xAF,0xE1,0x2F,0x00,0x07, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11600x1200_1_H[]= -{ - {{0x69,0x27,0x27,0x8D,0x30,0x88,0xC0,0x1F, - 0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x01, - 0x00}}, - {{0x69,0x27,0x27,0x8D,0x30,0x88,0x8E,0x1F, - 0x5E,0x82,0x5D,0x5D,0x87,0x10,0x00,0x01, - 0x00}}, - {{0x69,0x27,0x27,0x8D,0x30,0x88,0xC0,0x1F, - 0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x01, - 0x00}}, - {{0x69,0x27,0x27,0x8D,0x30,0x88,0x8E,0x1F, - 0x5E,0x82,0x5D,0x5D,0x87,0x10,0x00,0x01, - 0x00}}, - {{0x69,0x27,0x27,0x8D,0x30,0x88,0x10,0x3E, - 0xE0,0x84,0xDF,0xDF,0x11,0x00,0x00,0x01, - 0x00}}, - {{0x73,0x31,0x31,0x97,0x3A,0x92,0x88,0xF0, - 0x58,0x8C,0x57,0x57,0x89,0x20,0x00,0x01, - 0x01}}, - {{0x81,0x3F,0x3F,0x85,0x48,0x00,0x30,0xF5, - 0x00,0x84,0xFF,0xFF,0x31,0x10,0x00,0x06, - 0x01}}, - {{0x91,0x4F,0x4F,0x95,0x58,0x10,0x30,0x5A, - 0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x06, - 0x01}}, - {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A, - 0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03, - 0x01}}, - {{0xA5,0x63,0x63,0x89,0x6C,0x84,0xE0,0x10, - 0xB0,0x84,0xAF,0xAF,0xE1,0x2F,0x00,0x02, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11600x1200_2[]= -{ - {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E, - 0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x01,0x04, - 0x00}}, - {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E, - 0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x01,0x04, - 0x00}}, - {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E, - 0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x01,0x04, - 0x00}}, - {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E, - 0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x01,0x04, - 0x00}}, - {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E, - 0x5F,0x83,0xDF,0xDF,0xE1,0x01,0x01,0x04, - 0x00}}, - {{0x09,0x63,0x63,0x8D,0xAD,0x05,0xE0,0xD4, - 0x9B,0x8F,0x57,0x57,0xE1,0x21,0x01,0x00, - 0x01}}, - {{0x09,0x7F,0x7F,0x8D,0xBB,0x13,0xE0,0xD4, - 0xEF,0x83,0xFF,0xFF,0xE1,0x21,0x01,0x00, - 0x01}}, - {{0x09,0x9F,0x9F,0x8D,0xCB,0x03,0xE0,0x5A, - 0x6F,0x83,0xFF,0xFF,0xE1,0x29,0x01,0x04, - 0x01}}, - {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A, - 0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03, - 0x01}}, - {{0x09,0xC7,0xC7,0x8D,0xDF,0x17,0xE0,0x10, - 0xC7,0x8B,0xAF,0xAF,0xE1,0x0F,0x01,0x04, - 0x00}} -}; - -static const SiS310_LCDACRT1DataStruct SiS310_LCDACRT11600x1200_2_H[]= -{ - {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E, - 0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x00,0x03, - 0x00}}, - {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E, - 0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x00,0x03, - 0x00}}, - {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E, - 0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x00,0x03, - 0x00}}, - {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E, - 0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x00,0x03, - 0x00}}, - {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E, - 0x5F,0x83,0xDF,0xDF,0xE1,0x01,0x00,0x03, - 0x00}}, - {{0xD7,0x31,0x31,0x9B,0x7B,0x13,0xE0,0xD4, - 0x9B,0x8F,0x57,0x57,0xE1,0x21,0x00,0x03, - 0x01}}, - {{0xC9,0x3F,0x3F,0x8D,0x7B,0x13,0xE0,0xD4, - 0xEF,0x83,0xFF,0xFF,0xE1,0x21,0x00,0x03, - 0x01}}, - {{0xB9,0x4F,0x4F,0x9D,0x7B,0x93,0xE0,0x5A, - 0x6F,0x83,0xFF,0xFF,0xE1,0x29,0x00,0x02, - 0x01}}, - {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A, - 0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03, - 0x01}}, - {{0xA5,0x63,0x63,0x89,0x7B,0x93,0xE0,0x10, - 0xC7,0x8B,0xAF,0xAF,0xE1,0x0F,0x00,0x02, - 0x00}} -}; - +#endif /**************************************************************/ /* LVDS, CHRONTEL ------------------------------------------- */ /**************************************************************/ -typedef struct _SiS310_LVDSDataStruct -{ - USHORT VGAHT; - USHORT VGAVT; - USHORT LCDHT; - USHORT LCDVT; -} SiS310_LVDSDataStruct; - -static const SiS310_LVDSDataStruct SiS310_CHTVUPALData[]= +static const SiS_LVDSDataStruct SiS310_CHTVUPALData[]= { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1697,7 +982,7 @@ {1400,1000,1400,1000} }; -static const SiS310_LVDSDataStruct SiS310_CHTVOPALData[]= +static const SiS_LVDSDataStruct SiS310_CHTVOPALData[]= { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1708,7 +993,7 @@ {1400, 875,1400, 875} }; -static const SiS310_LVDSDataStruct SiS310_CHTVUPALMData[]= +static const SiS_LVDSDataStruct SiS310_CHTVUPALMData[]= { { 840, 600, 840, 600}, { 840, 600, 840, 600}, @@ -1719,7 +1004,7 @@ {1160, 945,1160, 945} }; -static const SiS310_LVDSDataStruct SiS310_CHTVOPALMData[]= +static const SiS_LVDSDataStruct SiS310_CHTVOPALMData[]= { { 840, 525, 840, 525}, { 840, 525, 840, 525}, @@ -1730,7 +1015,7 @@ {1160, 840,1160, 840} }; -static const SiS310_LVDSDataStruct SiS310_CHTVUPALNData[]= +static const SiS_LVDSDataStruct SiS310_CHTVUPALNData[]= { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1741,7 +1026,7 @@ {1400,1000,1400,1000} }; -static const SiS310_LVDSDataStruct SiS310_CHTVOPALNData[]= +static const SiS_LVDSDataStruct SiS310_CHTVOPALNData[]= { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1752,7 +1037,7 @@ {1400, 875,1400, 875} }; -static const SiS310_LVDSDataStruct SiS310_CHTVSOPALData[]= /* TW: (super overscan - no effect on 7019) */ +static const SiS_LVDSDataStruct SiS310_CHTVSOPALData[]= /* (super overscan - no effect on 7019) */ { {1008, 625,1008, 625}, {1008, 625,1008, 625}, @@ -1763,13 +1048,8 @@ {1400, 875,1400, 875} }; -typedef struct _SiS310_LVDSDesStruct -{ - USHORT LCDHDES; - USHORT LCDVDES; -} SiS310_LVDSDesStruct; -static const SiS310_LVDSDesStruct SiS310_PanelType00_1[]= /* 800x600 */ +static const SiS_LVDSDesStruct SiS310_PanelType00_1[]= /* 800x600 */ { { 0, 0}, { 0, 0}, @@ -1782,7 +1062,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType01_1[]= /* 1024x768 */ +static const SiS_LVDSDesStruct SiS310_PanelType01_1[]= /* 1024x768 */ { { 0, 0}, { 0, 0}, @@ -1795,7 +1075,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType02_1[]= /* 1280x1024 */ +static const SiS_LVDSDesStruct SiS310_PanelType02_1[]= /* 1280x1024 */ { { 0, 0}, { 0, 0}, @@ -1810,7 +1090,7 @@ }; -static const SiS310_LVDSDesStruct SiS310_PanelType03_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType03_1[]= { { 0, 0}, { 0, 0}, @@ -1823,7 +1103,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType04_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType04_1[]= { {1343, 798}, {1343, 794}, @@ -1836,7 +1116,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType05_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType05_1[]= { {1343, 798}, {1343, 794}, @@ -1849,7 +1129,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType06_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType06_1[]= { {1343, 798}, {1343, 794}, @@ -1862,7 +1142,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType07_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType07_1[]= { {1343, 798}, {1343, 794}, @@ -1875,7 +1155,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType08_1[]= /* 1400x1050 */ +static const SiS_LVDSDesStruct SiS310_PanelType08_1[]= /* 1400x1050 */ { { 0, 0}, { 0, 0}, @@ -1890,7 +1170,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType09_1[]= /* 1280x768 */ +static const SiS_LVDSDesStruct SiS310_PanelType09_1[]= /* 1280x768 */ { { 0, 0}, { 0, 0}, @@ -1905,7 +1185,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0a_1[]= /* 1600x1200 */ +static const SiS_LVDSDesStruct SiS310_PanelType0a_1[]= /* 1600x1200 */ { { 0, 0}, { 0, 0}, @@ -1920,7 +1200,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0b_1[]= /* 640x480_2 */ +static const SiS_LVDSDesStruct SiS310_PanelType0b_1[]= /* 640x480_2 */ { { 0, 524}, { 0, 524}, @@ -1932,7 +1212,7 @@ { 0, 524} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0c_1[]= /* 640x480_3 */ +static const SiS_LVDSDesStruct SiS310_PanelType0c_1[]= /* 640x480_3 */ { { 0, 524}, { 0, 524}, @@ -1944,7 +1224,7 @@ { 0, 524} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0d_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType0d_1[]= { {1343, 798}, {1343, 794}, @@ -1957,7 +1237,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0e_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType0e_1[]= { {1343, 798}, {1343, 794}, @@ -1970,7 +1250,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0f_1[]= +static const SiS_LVDSDesStruct SiS310_PanelType0f_1[]= { {1343, 798}, {1343, 794}, @@ -1983,7 +1263,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType00_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType00_2[]= { {980, 528}, {980, 503}, @@ -1996,7 +1276,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType01_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType01_2[]= { {1152, 622}, {1152, 597}, @@ -2009,7 +1289,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType02_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType02_2[]= { {1368, 754}, {1368, 729}, @@ -2024,7 +1304,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType03_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType03_2[]= { { 0, 0}, { 0, 0}, @@ -2035,7 +1315,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType04_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType04_2[]= { { 0, 0}, { 0, 0}, @@ -2048,7 +1328,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType05_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType05_2[]= { {1152, 622}, {1152, 597}, @@ -2061,7 +1341,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType06_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType06_2[]= { {1152, 622}, {1152, 597}, @@ -2074,7 +1354,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType07_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType07_2[]= { {1152, 622}, {1152, 597}, @@ -2087,7 +1367,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType08_2[]= /* 1400x1050 */ +static const SiS_LVDSDesStruct SiS310_PanelType08_2[]= /* 1400x1050 */ { {1308, 741}, {1308, 716}, @@ -2102,7 +1382,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType09_2[]= /* 1280x768 */ +static const SiS_LVDSDesStruct SiS310_PanelType09_2[]= /* 1280x768 */ { {1083, 622}, {1083, 597}, @@ -2115,7 +1395,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0a_2[]= /* 1600x1200 */ +static const SiS_LVDSDesStruct SiS310_PanelType0a_2[]= /* 1600x1200 */ { {1568, 920}, {1568, 895}, @@ -2141,7 +1421,7 @@ #endif }; -static const SiS310_LVDSDesStruct SiS310_PanelType0b_2[]= /* 640x480_2 */ +static const SiS_LVDSDesStruct SiS310_PanelType0b_2[]= /* 640x480_2 */ { {1152, 622}, {1152, 597}, @@ -2154,7 +1434,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0c_2[]= /* 640x480_3 */ +static const SiS_LVDSDesStruct SiS310_PanelType0c_2[]= /* 640x480_3 */ { {1152, 622}, {1152, 597}, @@ -2167,7 +1447,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0d_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType0d_2[]= { {1152, 622}, {1152, 597}, @@ -2180,7 +1460,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0e_2[]= +static const SiS_LVDSDesStruct SiS310_PanelType0e_2[]= { {1152, 622}, {1152, 597}, @@ -2193,7 +1473,7 @@ { 0, 0} }; -static const SiS310_LVDSDesStruct SiS310_PanelType0f_2[] = +static const SiS_LVDSDesStruct SiS310_PanelType0f_2[] = { {1152, 622}, {1152, 597}, @@ -2206,14 +1486,37 @@ { 0, 0} }; -/* CRT1 CRTC for SlaveModes and LCDA */ +static const SiS_LVDSDesStruct SiS310_PanelTypeNS_1[]= +{ + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 8, 0}, + { 0, 0}, + { 0, 0}, + { 0, 0}, + { 0, 806}, + { 0, 0} +}; -typedef struct _SiS310_LVDSCRT1DataStruct +static const SiS_LVDSDesStruct SiS310_PanelTypeNS_2[] = { - UCHAR CR[15]; -} SiS310_LVDSCRT1DataStruct; + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0}, + { 0 , 0} +}; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = +/* CRT1 CRTC for SlaveModes and LCDA */ + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1[] = { {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -2235,7 +1538,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_1_H[] = { {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f, 0x90,0x85,0x8f,0xab,0x30,0x00,0x05, @@ -2257,7 +1560,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[]= +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2[]= { {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e, 0xff,0x84,0x8f,0x73,0x00,0x00,0x06, @@ -2279,7 +1582,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1800x600_2_H[] = { {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e, 0xff,0x84,0x8f,0x73,0x00,0x00,0x01, @@ -2301,7 +1604,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1[] = { {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, @@ -2326,7 +1629,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_1_H[] = { {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f, 0x92,0x89,0x8f,0xb5,0x30,0x00,0x05, @@ -2351,7 +1654,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2[] = { {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb, 0x57,0x8e,0x8f,0x25,0x30,0x00,0x06, @@ -2376,7 +1679,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11024x768_2_H[] = { {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb, 0x57,0x8e,0x8f,0x25,0x30,0x00,0x01, @@ -2401,7 +1704,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1[] = { {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f, 0x90,0x84,0x8f,0xb9,0x30,0x00,0x06, @@ -2429,7 +1732,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_1_H[] = { {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f, 0x90,0x84,0x8f,0xb9,0x30,0x00,0x05, @@ -2454,7 +1757,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2[] = { {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92, 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02, @@ -2482,7 +1785,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11280x1024_2_H[] = { {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92, 0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06, @@ -2507,7 +1810,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1[] = { {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f, 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, @@ -2567,7 +1870,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_1_H[] = { {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f, 0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05, @@ -2627,7 +1930,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2[] = { {{0xce,0x72,0x91,0x84,0x92,0x28,0x92, 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02, @@ -2687,7 +1990,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11400x1050_2_H[] = { {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92, 0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06, @@ -2747,7 +2050,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1[] = { {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E, 0xB3,0x86,0x8F,0x07,0x20,0x00,0x06, @@ -2813,7 +2116,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_1_H[] = { {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E, 0xB3,0x86,0x8F,0x07,0x20,0x00,0x01, @@ -2879,7 +2182,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2[] = { {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97, 0x43,0x86,0xDB,0xDA,0x11,0x00,0x07, @@ -2945,7 +2248,7 @@ #endif }; -static const SiS310_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2_H[] = +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT11600x1200_2_H[] = { {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97, 0x43,0x86,0xDB,0xDA,0x11,0x00,0x02, @@ -3011,9 +2314,66 @@ #endif }; +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1[] = +{ + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, + 0x00}}, + {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, + 0x00}}, + {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, + 0x01}}, + {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x02, + 0x01}}, + {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, + 0x00,0x84,0xff,0x29,0x09,0x00,0x07, + 0x01}}, + {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x07, + 0x01}} +}; + +static const SiS_LVDSCRT1DataStruct SiS310_LVDSCRT1XXXxXXX_1_H[] = +{ + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, + 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, + 0x00}}, + {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, + 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, + 0x00}}, + {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, + 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, + 0x01}}, + {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, + 0x02,0x88,0xff,0x25,0x10,0x00,0x01, + 0x01}} +}; + + /* CRT1 CRTC for Chrontel TV slave modes */ -static const SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UNTSC[] = { {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e, 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01, @@ -3038,7 +2398,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1ONTSC[] = { {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e, 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01, @@ -3063,7 +2423,7 @@ 0x01 }} }; -static const SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1UPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -3088,7 +2448,7 @@ 0x01}} }; -static const SiS310_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = +static const SiS_LVDSCRT1DataStruct SiS310_CHTVCRT1OPAL[] = { {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e, 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05, @@ -3113,12 +2473,8 @@ 0x01 }} }; -typedef struct _SiS310_CHTVRegDataStruct -{ - UCHAR Reg[16]; -} SiS310_CHTVRegDataStruct; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = { {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3138,7 +2494,7 @@ for PAL-M and PAL-N all above is corrected. */ -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = { {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3149,7 +2505,7 @@ {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}} }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = { {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3160,7 +2516,7 @@ {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}} }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = { {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3171,7 +2527,7 @@ {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}} }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] = { {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3187,7 +2543,7 @@ #endif }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] = { {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}}, @@ -3203,7 +2559,7 @@ #endif }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] = { {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, @@ -3219,7 +2575,7 @@ #endif }; -static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] = +static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] = { {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}}, diff -urN linux-2.4.25/drivers/video/sis/init.c linux-2.4.26/drivers/video/sis/init.c --- linux-2.4.25/drivers/video/sis/init.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/init.c 2004-04-14 06:05:39.000000000 -0700 @@ -34,13 +34,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -78,7 +75,6 @@ #if defined(ALLOC_PRAGMA) #pragma alloc_text(PAGE,SiSSetMode) -#pragma alloc_text(PAGE,SiSInit) #endif /*********************************************/ @@ -108,17 +104,20 @@ SiS_Pr->SiS_PALTiming = SiS_PALTiming; SiS_Pr->SiS_HiTVSt1Timing = SiS_HiTVSt1Timing; SiS_Pr->SiS_HiTVSt2Timing = SiS_HiTVSt2Timing; - SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming; + SiS_Pr->SiS_HiTVExtTiming = SiS_HiTVExtTiming; SiS_Pr->SiS_HiTVGroup3Data = SiS_HiTVGroup3Data; SiS_Pr->SiS_HiTVGroup3Simu = SiS_HiTVGroup3Simu; +#if 0 + SiS_Pr->SiS_HiTVTextTiming = SiS_HiTVTextTiming; SiS_Pr->SiS_HiTVGroup3Text = SiS_HiTVGroup3Text; +#endif SiS_Pr->SiS_StPALData = SiS_StPALData; SiS_Pr->SiS_ExtPALData = SiS_ExtPALData; SiS_Pr->SiS_StNTSCData = SiS_StNTSCData; SiS_Pr->SiS_ExtNTSCData = SiS_ExtNTSCData; -/* SiS_Pr->SiS_St1HiTVData = SiS_St1HiTVData; */ + SiS_Pr->SiS_St1HiTVData = SiS_StHiTVData; SiS_Pr->SiS_St2HiTVData = SiS_St2HiTVData; SiS_Pr->SiS_ExtHiTVData = SiS_ExtHiTVData; SiS_Pr->SiS_St525iData = SiS_StNTSCData; @@ -131,16 +130,17 @@ SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect; SiS_Pr->pSiS_SoftSetting = &SiS_SoftSetting; + SiS_Pr->SiS_LCD1280x720Data = SiS_LCD1280x720Data; + SiS_Pr->SiS_StLCD1280x768_2Data = SiS_StLCD1280x768_2Data; + SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data; + SiS_Pr->SiS_LCD1280x768_3Data = SiS_LCD1280x768_3Data; + SiS_Pr->SiS_LCD1280x800Data = SiS_LCD1280x800Data; SiS_Pr->SiS_LCD1280x960Data = SiS_LCD1280x960Data; - SiS_Pr->SiS_ExtLCD1400x1050Data = SiS_ExtLCD1400x1050Data; - SiS_Pr->SiS_ExtLCD1600x1200Data = SiS_ExtLCD1600x1200Data; SiS_Pr->SiS_StLCD1400x1050Data = SiS_StLCD1400x1050Data; + SiS_Pr->SiS_ExtLCD1400x1050Data = SiS_ExtLCD1400x1050Data; + SiS_Pr->SiS_LCD1680x1050Data = SiS_LCD1680x1050Data; SiS_Pr->SiS_StLCD1600x1200Data = SiS_StLCD1600x1200Data; - SiS_Pr->SiS_NoScaleData1400x1050 = SiS_NoScaleData1400x1050; - SiS_Pr->SiS_NoScaleData1600x1200 = SiS_NoScaleData1600x1200; - SiS_Pr->SiS_ExtLCD1280x768Data = SiS_ExtLCD1280x768Data; - SiS_Pr->SiS_StLCD1280x768Data = SiS_StLCD1280x768Data; - SiS_Pr->SiS_NoScaleData1280x768 = SiS_NoScaleData1280x768; + SiS_Pr->SiS_ExtLCD1600x1200Data = SiS_ExtLCD1600x1200Data; SiS_Pr->SiS_NoScaleData = SiS_NoScaleData; SiS_Pr->SiS_LVDS320x480Data_1 = SiS_LVDS320x480Data_1; @@ -169,41 +169,12 @@ SiS_Pr->SiS_LVDS640x480Data_1 = SiS_LVDS640x480Data_1; SiS_Pr->SiS_LVDS640x480Data_2 = SiS_LVDS640x480Data_2; - SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1; - SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2; - SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1; - SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2; SiS_Pr->SiS_LVDS848x480Data_1 = SiS_LVDS848x480Data_1; SiS_Pr->SiS_LVDS848x480Data_2 = SiS_LVDS848x480Data_2; - - SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData; - SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData; - - SiS_Pr->SiS_LCDA1024x768Data_1 = SiS_LCDA1024x768Data_1; - SiS_Pr->SiS_LCDA1024x768Data_2 = SiS_LCDA1024x768Data_2; - SiS_Pr->SiS_LCDA1280x1024Data_1 = SiS_LCDA1280x1024Data_1; - SiS_Pr->SiS_LCDA1280x1024Data_2 = SiS_LCDA1280x1024Data_2; - SiS_Pr->SiS_LCDA1400x1050Data_1 = SiS_LCDA1400x1050Data_1; - SiS_Pr->SiS_LCDA1400x1050Data_2 = SiS_LCDA1400x1050Data_2; - SiS_Pr->SiS_LCDA1600x1200Data_1 = SiS_LCDA1600x1200Data_1; - SiS_Pr->SiS_LCDA1600x1200Data_2 = SiS_LCDA1600x1200Data_2; - - SiS_Pr->LVDS1024x768Des_1 = SiS_PanelType1076_1; - SiS_Pr->LVDS1280x1024Des_1 = SiS_PanelType1210_1; - SiS_Pr->LVDS1400x1050Des_1 = SiS_PanelType1296_1; - SiS_Pr->LVDS1600x1200Des_1 = SiS_PanelType1600_1; - SiS_Pr->LVDS1024x768Des_2 = SiS_PanelType1076_2; - SiS_Pr->LVDS1280x1024Des_2 = SiS_PanelType1210_2; - SiS_Pr->LVDS1400x1050Des_2 = SiS_PanelType1296_2; - SiS_Pr->LVDS1600x1200Des_2 = SiS_PanelType1600_2; - - SiS_Pr->SiS_PanelTypeNS_1 = SiS_PanelTypeNS_1; - SiS_Pr->SiS_PanelTypeNS_2 = SiS_PanelTypeNS_2; - - SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData; - SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData; - SiS_Pr->SiS_CHTVUPALDesData = SiS_CHTVUPALDesData; - SiS_Pr->SiS_CHTVOPALDesData = SiS_CHTVOPALDesData; + SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1; + SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2; + SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1; + SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2; SiS_Pr->SiS_LVDSCRT11280x768_1 = SiS_LVDSCRT11280x768_1; SiS_Pr->SiS_LVDSCRT11024x600_1 = SiS_LVDSCRT11024x600_1; @@ -218,14 +189,23 @@ SiS_Pr->SiS_LVDSCRT11024x600_2_H = SiS_LVDSCRT11024x600_2_H; SiS_Pr->SiS_LVDSCRT11152x768_2_H = SiS_LVDSCRT11152x768_2_H; SiS_Pr->SiS_LVDSCRT1320x480_1 = SiS_LVDSCRT1320x480_1; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS_LVDSCRT1XXXxXXX_1; - SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS_LVDSCRT1XXXxXXX_1_H; SiS_Pr->SiS_LVDSCRT1640x480_1 = SiS_LVDSCRT1640x480_1; SiS_Pr->SiS_LVDSCRT1640x480_1_H = SiS_LVDSCRT1640x480_1_H; SiS_Pr->SiS_LVDSCRT1640x480_2 = SiS_LVDSCRT1640x480_2; SiS_Pr->SiS_LVDSCRT1640x480_2_H = SiS_LVDSCRT1640x480_2_H; SiS_Pr->SiS_LVDSCRT1640x480_3 = SiS_LVDSCRT1640x480_3; SiS_Pr->SiS_LVDSCRT1640x480_3_H = SiS_LVDSCRT1640x480_3_H; + + SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData; + SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData; + + SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData; + SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData; + SiS_Pr->SiS_CHTVUPALDesData = SiS_CHTVUPALDesData; + SiS_Pr->SiS_CHTVOPALDesData = SiS_CHTVOPALDesData; + + SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* lowest value LVDS/LCDA */ + SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ } #ifdef SIS300 @@ -262,19 +242,18 @@ SiS_StandTable[0x1c].CRTC[4] = 0x54; SiS_StandTable[0x1c].CRTC[5] = 0x80; - SiS_Pr->SiS_SModeIDTable = (SiS_StStruct *)SiS300_SModeIDTable; - SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable; - SiS_Pr->SiS_EModeIDTable = (SiS_ExtStruct *)SiS300_EModeIDTable; - SiS_Pr->SiS_RefIndex = (SiS_Ext2Struct *)SiS300_RefIndex; - SiS_Pr->SiS_CRT1Table = (SiS_CRT1TableStruct *)SiS300_CRT1Table; + SiS_Pr->SiS_SModeIDTable = SiS300_SModeIDTable; + SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiS300_EModeIDTable; + SiS_Pr->SiS_RefIndex = SiS300_RefIndex; + SiS_Pr->SiS_CRT1Table = SiS300_CRT1Table; if(HwInfo->jChipType == SIS_300) { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS300_MCLKData_300; /* 300 */ + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_300; /* 300 */ } else { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630, 730 */ + SiS_Pr->SiS_MCLKData_0 = SiS300_MCLKData_630; /* 630, 730 */ } - SiS_Pr->SiS_VCLKData = (SiS_VCLKDataStruct *)SiS300_VCLKData; + SiS_Pr->SiS_VCLKData = SiS300_VCLKData; SiS_Pr->SiS_VBVCLKData = (SiS_VBVCLKDataStruct *)SiS300_VCLKData; - SiS_Pr->SiS_ScreenOffset = SiS300_ScreenOffset; SiS_Pr->SiS_SR15 = SiS300_SR15; @@ -303,97 +282,102 @@ SiS_Pr->pSiS_YCSenseData2 = &SiS300_YCSenseData2; #endif - SiS_Pr->SiS_StLCD1024x768Data = (SiS_LCDDataStruct *)SiS300_StLCD1024x768Data; - SiS_Pr->SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *)SiS300_ExtLCD1024x768Data; - SiS_Pr->SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *)SiS300_St2LCD1024x768Data; - SiS_Pr->SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *)SiS300_StLCD1280x1024Data; - SiS_Pr->SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *)SiS300_ExtLCD1280x1024Data; - SiS_Pr->SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *)SiS300_St2LCD1280x1024Data; - SiS_Pr->SiS_NoScaleData1024x768 = (SiS_LCDDataStruct *)SiS300_NoScaleData1024x768; - SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024; + SiS_Pr->SiS_PanelDelayTbl = SiS300_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl; - SiS_Pr->SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl; - SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl; -#if 0 - SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS; -#endif - - SiS_Pr->SiS_CHTVUPALData = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData; - SiS_Pr->SiS_CHTVOPALData = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData; - SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS300_CHTVSOPALData; - - SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS300_PanelType00_1; - SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS300_PanelType01_1; - SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS300_PanelType02_1; - SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS300_PanelType03_1; - SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1; - SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS300_PanelType05_1; - SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS300_PanelType06_1; - SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS300_PanelType07_1; - SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS300_PanelType08_1; - SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS300_PanelType09_1; - SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_1; - SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_1; - SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_1; - SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_1; - SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_1; - SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_1; - SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS300_PanelType00_2; - SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS300_PanelType01_2; - SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS300_PanelType02_2; - SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS300_PanelType03_2; - SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2; - SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS300_PanelType05_2; - SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS300_PanelType06_2; - SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS300_PanelType07_2; - SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS300_PanelType08_2; - SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS300_PanelType09_2; - SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_2; - SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_2; - SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_2; - SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_2; - SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_2; - SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_2; + SiS_Pr->SiS_ExtLCD1024x768Data = SiS300_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1024x768Data = SiS300_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS300_ExtLCD1280x1024Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS300_St2LCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS300_CRT2Part2_1024x768_1; + SiS_Pr->SiS_CRT2Part2_1280x1024_1 = SiS300_CRT2Part2_1280x1024_1; + SiS_Pr->SiS_CRT2Part2_1024x768_2 = SiS300_CRT2Part2_1024x768_2; + SiS_Pr->SiS_CRT2Part2_1280x1024_2 = SiS300_CRT2Part2_1280x1024_2; + SiS_Pr->SiS_CRT2Part2_1024x768_3 = SiS300_CRT2Part2_1024x768_3; + SiS_Pr->SiS_CRT2Part2_1280x1024_3 = SiS300_CRT2Part2_1280x1024_3; + + SiS_Pr->SiS_CHTVUPALData = SiS300_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS300_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData; + + SiS_Pr->SiS_PanelType00_1 = SiS300_PanelType00_1; + SiS_Pr->SiS_PanelType01_1 = SiS300_PanelType01_1; + SiS_Pr->SiS_PanelType02_1 = SiS300_PanelType02_1; + SiS_Pr->SiS_PanelType03_1 = SiS300_PanelType03_1; + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1; + SiS_Pr->SiS_PanelType05_1 = SiS300_PanelType05_1; + SiS_Pr->SiS_PanelType06_1 = SiS300_PanelType06_1; + SiS_Pr->SiS_PanelType07_1 = SiS300_PanelType07_1; + SiS_Pr->SiS_PanelType08_1 = SiS300_PanelType08_1; + SiS_Pr->SiS_PanelType09_1 = SiS300_PanelType09_1; + SiS_Pr->SiS_PanelType0a_1 = SiS300_PanelType0a_1; + SiS_Pr->SiS_PanelType0b_1 = SiS300_PanelType0b_1; + SiS_Pr->SiS_PanelType0c_1 = SiS300_PanelType0c_1; + SiS_Pr->SiS_PanelType0d_1 = SiS300_PanelType0d_1; + SiS_Pr->SiS_PanelType0e_1 = SiS300_PanelType0e_1; + SiS_Pr->SiS_PanelType0f_1 = SiS300_PanelType0f_1; + SiS_Pr->SiS_PanelType00_2 = SiS300_PanelType00_2; + SiS_Pr->SiS_PanelType01_2 = SiS300_PanelType01_2; + SiS_Pr->SiS_PanelType02_2 = SiS300_PanelType02_2; + SiS_Pr->SiS_PanelType03_2 = SiS300_PanelType03_2; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2; + SiS_Pr->SiS_PanelType05_2 = SiS300_PanelType05_2; + SiS_Pr->SiS_PanelType06_2 = SiS300_PanelType06_2; + SiS_Pr->SiS_PanelType07_2 = SiS300_PanelType07_2; + SiS_Pr->SiS_PanelType08_2 = SiS300_PanelType08_2; + SiS_Pr->SiS_PanelType09_2 = SiS300_PanelType09_2; + SiS_Pr->SiS_PanelType0a_2 = SiS300_PanelType0a_2; + SiS_Pr->SiS_PanelType0b_2 = SiS300_PanelType0b_2; + SiS_Pr->SiS_PanelType0c_2 = SiS300_PanelType0c_2; + SiS_Pr->SiS_PanelType0d_2 = SiS300_PanelType0d_2; + SiS_Pr->SiS_PanelType0e_2 = SiS300_PanelType0e_2; + SiS_Pr->SiS_PanelType0f_2 = SiS300_PanelType0f_2; + SiS_Pr->SiS_PanelTypeNS_1 = SiS300_PanelTypeNS_1; + SiS_Pr->SiS_PanelTypeNS_2 = SiS300_PanelTypeNS_2; if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1a; - SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2a; + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1a; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2a; } if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { - SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1b; - SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2b; + SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1b; + SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2b; } - SiS_Pr->SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1; - SiS_Pr->SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1; - SiS_Pr->SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1; - SiS_Pr->SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1_H; - SiS_Pr->SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1_H; - SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1_H; - SiS_Pr->SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2; - SiS_Pr->SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2; - SiS_Pr->SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2; - SiS_Pr->SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2_H; - SiS_Pr->SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2_H; - SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2_H; - SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UNTSC; - SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1ONTSC; - SiS_Pr->SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UPAL; - SiS_Pr->SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1OPAL; - SiS_Pr->SiS_CHTVCRT1SOPAL = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1SOPAL; - SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC; - SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC; - SiS_Pr->SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL; - SiS_Pr->SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL; - SiS_Pr->SiS_CHTVReg_UPALM = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVReg_OPALM = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL; /* not supported on 300 series */ - SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_SOPAL; + SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS300_LVDSCRT1800x600_1; + SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS300_LVDSCRT1800x600_1_H; + SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS300_LVDSCRT1800x600_2; + SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS300_LVDSCRT1800x600_2_H; + SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS300_LVDSCRT11024x768_1; + SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS300_LVDSCRT11024x768_1_H; + SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS300_LVDSCRT11024x768_2; + SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS300_LVDSCRT11024x768_2_H; + SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS300_LVDSCRT11280x1024_1; + SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS300_LVDSCRT11280x1024_1_H; + SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS300_LVDSCRT11280x1024_2; + SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS300_LVDSCRT11280x1024_2_H; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS300_LVDSCRT1XXXxXXX_1; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS300_LVDSCRT1XXXxXXX_1_H; + + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS300_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS300_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL; + SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS300_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS300_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL; /* not supported on 300 series */ + SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL; SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC; SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC; SiS_Pr->SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL; @@ -403,40 +387,6 @@ SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL; /* not supported on 300 series */ SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL; /* not supported on 300 series */ SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL; - - SiS_Pr->SiS_CRT2Part2_1024x768_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_1; - SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_1; - SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_1; - SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_1; - SiS_Pr->SiS_CRT2Part2_1024x768_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_2; - SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_2; - SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_2; - SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_2; - SiS_Pr->SiS_CRT2Part2_1024x768_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_3; - SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_3; - SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_3; - SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_3; - - /* LCDResInfo will on 300 series be translated to 315 series definitions */ - SiS_Pr->SiS_Panel320x480 = Panel_320x480; - SiS_Pr->SiS_Panel640x480 = Panel_640x480; - SiS_Pr->SiS_Panel800x600 = Panel_800x600; - SiS_Pr->SiS_Panel1024x768 = Panel_1024x768; - SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024; - SiS_Pr->SiS_Panel1280x960 = Panel_1280x960; - SiS_Pr->SiS_Panel1024x600 = Panel_1024x600; - SiS_Pr->SiS_Panel1152x768 = Panel_1152x768; - SiS_Pr->SiS_Panel1280x768 = Panel_1280x768; - SiS_Pr->SiS_Panel1600x1200 = 255; /* Something illegal */ - SiS_Pr->SiS_Panel1400x1050 = 255; - SiS_Pr->SiS_Panel640x480_2 = 255; - SiS_Pr->SiS_Panel640x480_3 = 255; - SiS_Pr->SiS_Panel1152x864 = 255; - SiS_Pr->SiS_PanelMax = Panel_320x480; /* highest value */ - SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* Lowest value LVDS */ - SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ - SiS_Pr->SiS_PanelCustom = Panel_Custom; - SiS_Pr->SiS_PanelBarco1366 = Panel_Barco1366; } #endif @@ -474,23 +424,24 @@ SiS_StandTable[0x1c].CRTC[4] = 0x55; SiS_StandTable[0x1c].CRTC[5] = 0x81; - SiS_Pr->SiS_SModeIDTable = (SiS_StStruct *)SiS310_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = (SiS_ExtStruct *)SiS310_EModeIDTable; + SiS_Pr->SiS_SModeIDTable = SiS310_SModeIDTable; + SiS_Pr->SiS_EModeIDTable = SiS310_EModeIDTable; SiS_Pr->SiS_RefIndex = (SiS_Ext2Struct *)SiS310_RefIndex; - SiS_Pr->SiS_CRT1Table = (SiS_CRT1TableStruct *)SiS310_CRT1Table; - if(HwInfo->jChipType >= SIS_661) { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660; /* 661/741/760 */ + SiS_Pr->SiS_CRT1Table = SiS310_CRT1Table; + if(HwInfo->jChipType >= SIS_760) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760; /* 760 */ + } else if(HwInfo->jChipType >= SIS_661) { + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660; /* 661/741 */ } else if(HwInfo->jChipType == SIS_330) { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_330; /* 330 */ + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330; /* 330 */ } else if(HwInfo->jChipType > SIS_315PRO) { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650; /* 550, 650, 740 */ + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650; /* 550, 650, 740 */ } else { - SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315; /* 315 */ + SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315; /* 315 */ } - SiS_Pr->SiS_MCLKData_1 = (SiS_MCLKDataStruct *)SiS310_MCLKData_1; - SiS_Pr->SiS_VCLKData = (SiS_VCLKDataStruct *)SiS310_VCLKData; - SiS_Pr->SiS_VBVCLKData = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData; - SiS_Pr->SiS_ScreenOffset = SiS310_ScreenOffset; + SiS_Pr->SiS_MCLKData_1 = SiS310_MCLKData_1; + SiS_Pr->SiS_VCLKData = SiS310_VCLKData; + SiS_Pr->SiS_VBVCLKData = SiS310_VBVCLKData; SiS_Pr->SiS_SR15 = SiS310_SR15; @@ -519,124 +470,96 @@ SiS_Pr->pSiS_YCSenseData2 = &SiS310_YCSenseData2; #endif - SiS_Pr->SiS_StLCD1024x768Data = (SiS_LCDDataStruct *)SiS310_StLCD1024x768Data; - SiS_Pr->SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *)SiS310_ExtLCD1024x768Data; - SiS_Pr->SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *)SiS310_St2LCD1024x768Data; - SiS_Pr->SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *)SiS310_StLCD1280x1024Data; - SiS_Pr->SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *)SiS310_ExtLCD1280x1024Data; - SiS_Pr->SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *)SiS310_St2LCD1280x1024Data; - SiS_Pr->SiS_NoScaleData1024x768 = (SiS_LCDDataStruct *)SiS310_NoScaleData1024x768; - SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS310_NoScaleData1280x1024; - - SiS_Pr->SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl; - SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTblLVDS; - - SiS_Pr->SiS_CHTVUPALData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALData; - SiS_Pr->SiS_CHTVOPALData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALData; - SiS_Pr->SiS_CHTVUPALMData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALMData; - SiS_Pr->SiS_CHTVOPALMData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALMData; - SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALNData; - SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALNData; - SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS310_CHTVSOPALData; - - SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS310_PanelType00_1; - SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS310_PanelType01_1; - SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS310_PanelType02_1; - SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS310_PanelType03_1; - SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS310_PanelType04_1; - SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS310_PanelType05_1; - SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS310_PanelType06_1; - SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS310_PanelType07_1; - SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS310_PanelType08_1; - SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS310_PanelType09_1; - SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_1; - SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_1; - SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_1; - SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_1; - SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_1; - SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_1; - SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS310_PanelType00_2; - SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS310_PanelType01_2; - SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS310_PanelType02_2; - SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS310_PanelType03_2; - SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS310_PanelType04_2; - SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS310_PanelType05_2; - SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS310_PanelType06_2; - SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS310_PanelType07_2; - SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS310_PanelType08_2; - SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS310_PanelType09_2; - SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_2; - SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_2; - SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_2; - SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_2; - SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_2; - SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_2; - - SiS_Pr->SiS_CRT2Part2_1024x768_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_1; - SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_1; - SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_1; - SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_1; - SiS_Pr->SiS_CRT2Part2_1024x768_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_2; - SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_2; - SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_2; - SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_2; - SiS_Pr->SiS_CRT2Part2_1024x768_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_3; - SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_3; - SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_3; - SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_3; - - SiS_Pr->SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1; - SiS_Pr->SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1; - SiS_Pr->SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1; - SiS_Pr->SiS_LVDSCRT11400x1050_1 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1; - SiS_Pr->SiS_LVDSCRT11600x1200_1 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1; - SiS_Pr->SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1_H; - SiS_Pr->SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1_H; - SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1_H; - SiS_Pr->SiS_LVDSCRT11400x1050_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1_H; - SiS_Pr->SiS_LVDSCRT11600x1200_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1_H; - SiS_Pr->SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2; - SiS_Pr->SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2; - SiS_Pr->SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2; - SiS_Pr->SiS_LVDSCRT11400x1050_2 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2; - SiS_Pr->SiS_LVDSCRT11600x1200_2 = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2; - SiS_Pr->SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2_H; - SiS_Pr->SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2_H; - SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2_H; - SiS_Pr->SiS_LVDSCRT11400x1050_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2_H; - SiS_Pr->SiS_LVDSCRT11600x1200_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2_H; - SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC; - SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC; - SiS_Pr->SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL; - SiS_Pr->SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL; - SiS_Pr->SiS_CHTVCRT1SOPAL = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL; - - SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC; - SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC; - SiS_Pr->SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPAL; - SiS_Pr->SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL; - SiS_Pr->SiS_CHTVReg_UPALM = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALM; - SiS_Pr->SiS_CHTVReg_OPALM = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALM; - SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALN; - SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALN; - SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL; - - SiS_Pr->SiS_LCDACRT11024x768_1 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1; - SiS_Pr->SiS_LCDACRT11280x1024_1 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1; - SiS_Pr->SiS_LCDACRT11400x1050_1 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1; - SiS_Pr->SiS_LCDACRT11600x1200_1 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1; - SiS_Pr->SiS_LCDACRT11024x768_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1_H; - SiS_Pr->SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1_H; - SiS_Pr->SiS_LCDACRT11400x1050_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1_H; - SiS_Pr->SiS_LCDACRT11600x1200_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1_H; - SiS_Pr->SiS_LCDACRT11024x768_2 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2; - SiS_Pr->SiS_LCDACRT11280x1024_2 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2; - SiS_Pr->SiS_LCDACRT11400x1050_2 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2; - SiS_Pr->SiS_LCDACRT11600x1200_2 = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2; - SiS_Pr->SiS_LCDACRT11024x768_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2_H; - SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H; - SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H; - SiS_Pr->SiS_LCDACRT11600x1200_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2_H; + SiS_Pr->SiS_PanelDelayTbl = SiS310_PanelDelayTbl; + SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS; + + SiS_Pr->SiS_St2LCD1024x768Data = SiS310_St2LCD1024x768Data; + SiS_Pr->SiS_ExtLCD1024x768Data = SiS310_ExtLCD1024x768Data; + SiS_Pr->SiS_St2LCD1280x1024Data = SiS310_St2LCD1280x1024Data; + SiS_Pr->SiS_ExtLCD1280x1024Data = SiS310_ExtLCD1280x1024Data; + + SiS_Pr->SiS_CRT2Part2_1024x768_1 = SiS310_CRT2Part2_1024x768_1; + + SiS_Pr->SiS_PanelType00_1 = SiS310_PanelType00_1; + SiS_Pr->SiS_PanelType01_1 = SiS310_PanelType01_1; + SiS_Pr->SiS_PanelType02_1 = SiS310_PanelType02_1; + SiS_Pr->SiS_PanelType03_1 = SiS310_PanelType03_1; + SiS_Pr->SiS_PanelType04_1 = SiS310_PanelType04_1; + SiS_Pr->SiS_PanelType05_1 = SiS310_PanelType05_1; + SiS_Pr->SiS_PanelType06_1 = SiS310_PanelType06_1; + SiS_Pr->SiS_PanelType07_1 = SiS310_PanelType07_1; + SiS_Pr->SiS_PanelType08_1 = SiS310_PanelType08_1; + SiS_Pr->SiS_PanelType09_1 = SiS310_PanelType09_1; + SiS_Pr->SiS_PanelType0a_1 = SiS310_PanelType0a_1; + SiS_Pr->SiS_PanelType0b_1 = SiS310_PanelType0b_1; + SiS_Pr->SiS_PanelType0c_1 = SiS310_PanelType0c_1; + SiS_Pr->SiS_PanelType0d_1 = SiS310_PanelType0d_1; + SiS_Pr->SiS_PanelType0e_1 = SiS310_PanelType0e_1; + SiS_Pr->SiS_PanelType0f_1 = SiS310_PanelType0f_1; + SiS_Pr->SiS_PanelType00_2 = SiS310_PanelType00_2; + SiS_Pr->SiS_PanelType01_2 = SiS310_PanelType01_2; + SiS_Pr->SiS_PanelType02_2 = SiS310_PanelType02_2; + SiS_Pr->SiS_PanelType03_2 = SiS310_PanelType03_2; + SiS_Pr->SiS_PanelType04_2 = SiS310_PanelType04_2; + SiS_Pr->SiS_PanelType05_2 = SiS310_PanelType05_2; + SiS_Pr->SiS_PanelType06_2 = SiS310_PanelType06_2; + SiS_Pr->SiS_PanelType07_2 = SiS310_PanelType07_2; + SiS_Pr->SiS_PanelType08_2 = SiS310_PanelType08_2; + SiS_Pr->SiS_PanelType09_2 = SiS310_PanelType09_2; + SiS_Pr->SiS_PanelType0a_2 = SiS310_PanelType0a_2; + SiS_Pr->SiS_PanelType0b_2 = SiS310_PanelType0b_2; + SiS_Pr->SiS_PanelType0c_2 = SiS310_PanelType0c_2; + SiS_Pr->SiS_PanelType0d_2 = SiS310_PanelType0d_2; + SiS_Pr->SiS_PanelType0e_2 = SiS310_PanelType0e_2; + SiS_Pr->SiS_PanelType0f_2 = SiS310_PanelType0f_2; + SiS_Pr->SiS_PanelTypeNS_1 = SiS310_PanelTypeNS_1; + SiS_Pr->SiS_PanelTypeNS_2 = SiS310_PanelTypeNS_2; + + SiS_Pr->SiS_CHTVUPALData = SiS310_CHTVUPALData; + SiS_Pr->SiS_CHTVOPALData = SiS310_CHTVOPALData; + SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData; + SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData; + SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData; + SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData; + SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData; + + SiS_Pr->SiS_LVDSCRT1800x600_1 = SiS310_LVDSCRT1800x600_1; + SiS_Pr->SiS_LVDSCRT11024x768_1 = SiS310_LVDSCRT11024x768_1; + SiS_Pr->SiS_LVDSCRT11280x1024_1 = SiS310_LVDSCRT11280x1024_1; + SiS_Pr->SiS_LVDSCRT11400x1050_1 = SiS310_LVDSCRT11400x1050_1; + SiS_Pr->SiS_LVDSCRT11600x1200_1 = SiS310_LVDSCRT11600x1200_1; + SiS_Pr->SiS_LVDSCRT1800x600_1_H = SiS310_LVDSCRT1800x600_1_H; + SiS_Pr->SiS_LVDSCRT11024x768_1_H = SiS310_LVDSCRT11024x768_1_H; + SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS310_LVDSCRT11280x1024_1_H; + SiS_Pr->SiS_LVDSCRT11400x1050_1_H = SiS310_LVDSCRT11400x1050_1_H; + SiS_Pr->SiS_LVDSCRT11600x1200_1_H = SiS310_LVDSCRT11600x1200_1_H; + SiS_Pr->SiS_LVDSCRT1800x600_2 = SiS310_LVDSCRT1800x600_2; + SiS_Pr->SiS_LVDSCRT11024x768_2 = SiS310_LVDSCRT11024x768_2; + SiS_Pr->SiS_LVDSCRT11280x1024_2 = SiS310_LVDSCRT11280x1024_2; + SiS_Pr->SiS_LVDSCRT11400x1050_2 = SiS310_LVDSCRT11400x1050_2; + SiS_Pr->SiS_LVDSCRT11600x1200_2 = SiS310_LVDSCRT11600x1200_2; + SiS_Pr->SiS_LVDSCRT1800x600_2_H = SiS310_LVDSCRT1800x600_2_H; + SiS_Pr->SiS_LVDSCRT11024x768_2_H = SiS310_LVDSCRT11024x768_2_H; + SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS310_LVDSCRT11280x1024_2_H; + SiS_Pr->SiS_LVDSCRT11400x1050_2_H = SiS310_LVDSCRT11400x1050_2_H; + SiS_Pr->SiS_LVDSCRT11600x1200_2_H = SiS310_LVDSCRT11600x1200_2_H; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1 = SiS310_LVDSCRT1XXXxXXX_1; + SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H = SiS310_LVDSCRT1XXXxXXX_1_H; + SiS_Pr->SiS_CHTVCRT1UNTSC = SiS310_CHTVCRT1UNTSC; + SiS_Pr->SiS_CHTVCRT1ONTSC = SiS310_CHTVCRT1ONTSC; + SiS_Pr->SiS_CHTVCRT1UPAL = SiS310_CHTVCRT1UPAL; + SiS_Pr->SiS_CHTVCRT1OPAL = SiS310_CHTVCRT1OPAL; + SiS_Pr->SiS_CHTVCRT1SOPAL = SiS310_CHTVCRT1OPAL; + + SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC; + SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC; + SiS_Pr->SiS_CHTVReg_UPAL = SiS310_CHTVReg_UPAL; + SiS_Pr->SiS_CHTVReg_OPAL = SiS310_CHTVReg_OPAL; + SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM; + SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM; + SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN; + SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN; + SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL; SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC; SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC; @@ -645,28 +568,8 @@ SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM; SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM; SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN; - SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN; + SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN; SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL; - - SiS_Pr->SiS_Panel320x480 = Panel_320x480; - SiS_Pr->SiS_Panel640x480 = Panel_640x480; - SiS_Pr->SiS_Panel800x600 = Panel_800x600; - SiS_Pr->SiS_Panel1024x768 = Panel_1024x768; - SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024; - SiS_Pr->SiS_Panel1280x960 = Panel_1280x960; - SiS_Pr->SiS_Panel1600x1200 = Panel_1600x1200; - SiS_Pr->SiS_Panel1400x1050 = Panel_1400x1050; - SiS_Pr->SiS_Panel1152x768 = Panel_1152x768; - SiS_Pr->SiS_Panel1152x864 = Panel_1152x864; - SiS_Pr->SiS_Panel1280x768 = Panel_1280x768; - SiS_Pr->SiS_Panel1024x600 = Panel_1024x600; - SiS_Pr->SiS_Panel640x480_2 = Panel_640x480_2; - SiS_Pr->SiS_Panel640x480_3 = Panel_640x480_3; - SiS_Pr->SiS_PanelMax = Panel_320x480; /* highest value */ - SiS_Pr->SiS_PanelMinLVDS = Panel_800x600; /* lowest value LVDS/LCDA */ - SiS_Pr->SiS_PanelMin301 = Panel_1024x768; /* lowest value 301 */ - SiS_Pr->SiS_PanelCustom = Panel_Custom; - SiS_Pr->SiS_PanelBarco1366 = 255; } #endif @@ -707,7 +610,8 @@ /*********************************************/ USHORT -SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN) +SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight) { USHORT ModeIndex = 0; @@ -775,10 +679,23 @@ } break; case 1280: - if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; - else if(!(VBFlags & CRT1_LCDA)) { + if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; + else if(VDisplay == 800) { + if(VGAEngine == SIS_315_VGA) { + if((VBFlags & CRT1_LCDA) && (LCDwidth == 1280) && (LCDheight == 800)) { + ModeIndex = ModeIndex_1280x800[Depth]; + } else if(!(VBFlags & CRT1_LCDA)) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + } + } else if(VDisplay == 720) { + if((VBFlags & CRT1_LCDA) && (LCDwidth == 1280) && (LCDheight == 720)) { + ModeIndex = ModeIndex_1280x720[Depth]; + } else if(!(VBFlags & CRT1_LCDA)) { + ModeIndex = ModeIndex_1280x720[Depth]; + } + } else if(!(VBFlags & CRT1_LCDA)) { if(VDisplay == 960) ModeIndex = ModeIndex_1280x960[Depth]; - else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth]; else if(VDisplay == 768) { if(VGAEngine == SIS_300_VGA) { ModeIndex = ModeIndex_300_1280x768[Depth]; @@ -798,12 +715,25 @@ break; case 1400: if(VGAEngine == SIS_315_VGA) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + if(VDisplay == 1050) { + if((VBFlags & CRT1_LCDA) && + (((LCDwidth == 1400) && (LCDheight == 1050)) || + ((LCDwidth == 1600) && (LCDheight == 1200)))) { + ModeIndex = ModeIndex_1400x1050[Depth]; + } else if(!(VBFlags & CRT1_LCDA)) { + ModeIndex = ModeIndex_1400x1050[Depth]; + } + } } break; case 1600: if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + break; case 1920: if(!(VBFlags & CRT1_LCDA)) { if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth]; @@ -848,14 +778,18 @@ break; case 400: if(CustomT != CUT_PANEL848) { - if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { + if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; + } } break; case 512: if(CustomT != CUT_PANEL848) { - if(VDisplay == 384) { + if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) { if(LCDwidth != 1024 || LCDheight != 600) { - ModeIndex = ModeIndex_512x384[Depth]; + if(VDisplay == 384) { + ModeIndex = ModeIndex_512x384[Depth]; + } } } } @@ -895,6 +829,9 @@ if((VDisplay == 768) && (LCDheight == 768)) { ModeIndex = ModeIndex_310_1280x768[Depth]; } + if((VDisplay == 800) && (LCDheight == 800)) { + ModeIndex = ModeIndex_310_1280x768[Depth]; + } } break; case 1360: @@ -946,7 +883,7 @@ case 1280: if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; else if(VDisplay == 768) { - if((LCDheight == 768) || + if((LCDheight == 768) || (LCDwidth == 1680) || ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) { if(VGAEngine == SIS_300_VGA) { ModeIndex = ModeIndex_300_1280x768[Depth]; @@ -959,20 +896,41 @@ ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) { ModeIndex = ModeIndex_1280x960[Depth]; } + } else if(VGAEngine == SIS_315_VGA) { + if(VDisplay == 800) { + if((LCDheight == 800) || (LCDwidth == 1680) || + ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) { + ModeIndex = ModeIndex_1280x800[Depth]; + } + } else if(VDisplay == 720) { + if((LCDheight == 720) || (LCDwidth == 1680) || + ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) { + ModeIndex = ModeIndex_1280x720[Depth]; + } + } } break; case 1400: if(VGAEngine == SIS_315_VGA) { if(VBFlags & (VB_301B | VB_301C | VB_302B | VB_302LV | VB_302ELV)) { - if(LCDheight != 1200) { - if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth]; + if((LCDwidth == 1400) || (LCDwidth == 1600) || (LCDwidth == 1680)) { + ModeIndex = ModeIndex_1400x1050[Depth]; } } } break; case 1600: - if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) { - if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) { + if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth]; + } + } + break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } } break; } @@ -1021,8 +979,8 @@ if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth]; break; case 512: - if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR525P | TV_YPBPR750P))) || - (VBFlags & TV_HIVISION) || + if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) || + (VBFlags & TV_HIVISION) || ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth]; } @@ -1032,19 +990,21 @@ else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth]; break; case 720: - if(!(VBFlags & TV_HIVISION)) { + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { if(VDisplay == 480) { if((VBFlags & TV_YPBPR) || (VBFlags & (TV_NTSC | TV_PALM))) ModeIndex = ModeIndex_720x480[Depth]; } else if(VDisplay == 576) { - if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) ModeIndex = ModeIndex_720x576[Depth]; } } break; case 768: - if(!(VBFlags & TV_HIVISION)) { - if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) { + if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) { + if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) || + ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) { if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth]; } } @@ -1052,7 +1012,7 @@ case 800: if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth]; else if(VDisplay == 480) { - if(VBFlags & TV_HIVISION) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { ModeIndex = ModeIndex_800x480[Depth]; } } @@ -1063,15 +1023,22 @@ ModeIndex = ModeIndex_1024x768[Depth]; } } else if(VDisplay == 576) { - if(VBFlags & TV_HIVISION) { + if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { ModeIndex = ModeIndex_1024x576[Depth]; } } break; case 1280: - if(VBFlags & TV_HIVISION) { - if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth]; - else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; + if(VDisplay == 720) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) { + ModeIndex = ModeIndex_1280x720[Depth]; + } + } else if(VDisplay == 1024) { + if((VBFlags & TV_HIVISION) || + ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) { + ModeIndex = ModeIndex_1280x1024[Depth]; + } } break; } @@ -1138,6 +1105,7 @@ } } else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth]; else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth]; + else if(VDisplay == 800) ModeIndex = ModeIndex_1280x800[Depth]; else if(VDisplay == 960) ModeIndex = ModeIndex_1280x960[Depth]; break; case 1360: @@ -1155,6 +1123,13 @@ } } break; + case 1680: + if(VGAEngine == SIS_315_VGA) { + if(VBFlags & (VB_301B|VB_301C|VB_302B)) { + if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth]; + } + } + break; } return ModeIndex; @@ -1252,13 +1227,13 @@ void SiS_DisplayOn(SiS_Private *SiS_Pr) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF); } void SiS_DisplayOff(SiS_Private *SiS_Pr) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20); } @@ -1301,6 +1276,15 @@ { unsigned char cr5f, temp1, temp2; + /* 661 and newer: NEVER write non-zero to SR11[7:4] */ + /* (SR11 is used for DDC and in enable/disablebridge) */ + SiS_Pr->SiS_SensibleSR11 = FALSE; + SiS_Pr->SiS_MyCR63 = 0x63; + if(HwInfo->jChipType >= SIS_661) { + SiS_Pr->SiS_SensibleSR11 = TRUE; + SiS_Pr->SiS_MyCR63 = 0x53; + } + /* You should use the macros, not these flags directly */ SiS_Pr->SiS_SysFlags = 0; @@ -1338,6 +1322,10 @@ } } } + if(HwInfo->jChipType == SIS_760) { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78); + if(temp1 & 0x30) SiS_Pr->SiS_SysFlags |= SF_760UMA; + } } /*********************************************/ @@ -1410,18 +1398,19 @@ SiS_Pr->SiS_ChrontelInit = 0; + /* Check for SiS30x first */ + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); + if((temp == 1) || (temp == 2)) return; + switch(HwInfo->jChipType) { #ifdef SIS300 case SIS_540: case SIS_630: case SIS_730: - /* Check for SiS30x first */ - temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); - if((temp == 1) || (temp == 2)) return; temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); temp = (temp & 0x0E) >> 1; - if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; + if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_TRUMPION = 1; if((temp == 4) || (temp == 5)) { /* Save power status (and error check) - UNUSED */ SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e); @@ -1436,8 +1425,8 @@ case SIS_330: temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); temp = (temp & 0x0E) >> 1; - if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; break; case SIS_661: case SIS_741: @@ -1445,9 +1434,9 @@ case SIS_760: temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); temp = (temp & 0xe0) >> 5; - if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; - if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; - if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ + if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1; + if(temp == 3) SiS_Pr->SiS_IF_DEF_CH70xx = 2; + if(temp == 4) SiS_Pr->SiS_IF_DEF_CONEX = 1; /* Not yet supported */ break; #endif default: @@ -1475,44 +1464,72 @@ /* HELPER: Determine ROM usage */ /*********************************************/ +BOOLEAN +SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romversoffs, romvmaj = 1, romvmin = 0; + + if(HwInfo->jChipType >= SIS_661) { + romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8); + if(romversoffs) { + if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) { + romvmaj = ROMAddr[romversoffs] - '0'; + romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0'); + } + } + if((romvmaj != 0) || (romvmin >= 92)) { + return TRUE; + } + } else if(IS_SIS650740) { + if((ROMAddr[0x1a] == 'N') && + (ROMAddr[0x1b] == 'e') && + (ROMAddr[0x1c] == 'w') && + (ROMAddr[0x1d] == 'V')) { + return TRUE; + } + } + return FALSE; +} + static void SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr = 0; + + SiS_Pr->SiS_UseROM = FALSE; + SiS_Pr->SiS_ROMNew = FALSE; if((ROMAddr) && (HwInfo->UseROM)) { - if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) { - SiS_Pr->SiS_UseROM = FALSE; - } else if(HwInfo->jChipType == SIS_300) { - /* 300: We check if the code starts below 0x220 by - * checking the jmp instruction at the beginning - * of the BIOS image. - */ - if((ROMAddr[3] == 0xe9) && - ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a) + if(HwInfo->jChipType == SIS_300) { + /* 300: We check if the code starts below 0x220 by + * checking the jmp instruction at the beginning + * of the BIOS image. + */ + if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a) SiS_Pr->SiS_UseROM = TRUE; - else - SiS_Pr->SiS_UseROM = FALSE; } else if(HwInfo->jChipType < SIS_315H) { -#if 0 - /* Rest of 300 series: We don't use the ROM image if - * the BIOS version < 2.0.0 as such old BIOSes don't - * have the needed data at the expected locations. - */ - if(ROMAddr[0x06] < '2') SiS_Pr->SiS_UseROM = FALSE; - else SiS_Pr->SiS_UseROM = TRUE; -#else - /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps - * the others do as well - */ + /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps + * the others do as well + */ SiS_Pr->SiS_UseROM = TRUE; -#endif } else { /* 315/330 series stick to the standard */ SiS_Pr->SiS_UseROM = TRUE; + if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr, HwInfo))) { + /* Find out about LCD data table entry size */ + if((romptr = SISGETROMW(0x0102))) { + if(ROMAddr[romptr + (32 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 32; + else if(ROMAddr[romptr + (34 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 34; + else if(ROMAddr[romptr + (36 * 16)] == 0xff) + SiS_Pr->SiS661LCD2TableSize = 36; + } + } } - } else SiS_Pr->SiS_UseROM = FALSE; - + } } /*********************************************/ @@ -1597,7 +1614,8 @@ SiS_Pr->SiS_VBType = 0; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return; + if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX)) + return; flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00); @@ -1608,7 +1626,6 @@ if(flag >= 2) { SiS_Pr->SiS_VBType = VB_SIS302B; } else if(flag == 1) { - SiS_Pr->SiS_VBType = VB_SIS301; if(rev >= 0xC0) { SiS_Pr->SiS_VBType = VB_SIS301C; } else if(rev >= 0xB0) { @@ -1616,20 +1633,17 @@ /* Check if 30xB DH version (no LCD support, use Panel Link instead) */ nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23); if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD; + } else { + SiS_Pr->SiS_VBType = VB_SIS301; } } if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) { - if(rev >= 0xD0) { - SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_NoLCD); - if(rev >= 0xE0) { - flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); - if(flag == 0xff) - SiS_Pr->SiS_VBType |= VB_SIS302LV; - else - SiS_Pr->SiS_VBType |= VB_SIS302ELV; - } else { - SiS_Pr->SiS_VBType |= VB_SIS301LV; - } + if(rev >= 0xE0) { + flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39); + if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV; + else SiS_Pr->SiS_VBType = VB_SIS302ELV; + } else if(rev >= 0xD0) { + SiS_Pr->SiS_VBType = VB_SIS301LV; } } } @@ -1685,12 +1699,24 @@ case SIS_661: case SIS_741: - case SIS_660: - case SIS_760: counter = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x79) & 0xf0) >> 4; AdapterMemorySize = 1 << counter; AdapterMemorySize *= (1024*1024); break; + + case SIS_660: + case SIS_760: + counter = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x79) & 0xf0) >> 4; + if(counter) { + AdapterMemorySize = 1 << counter; + AdapterMemorySize *= (1024*1024); + } + counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x78) & 0x30; + if(counter) { + if(counter == 0x10) AdapterMemorySize += (32 * 1024 * 1024); + else AdapterMemorySize += (64 * 1024 * 1024); + } + break; #endif #ifdef SIS300 @@ -1758,7 +1784,10 @@ if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) { data = *SiS_Pr->pSiS_SoftSetting & 0x03; } else { - if(HwInfo->jChipType >= SIS_661) { + if(HwInfo->jChipType >= SIS_660) { + /* data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; */ + data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6); + } else if(HwInfo->jChipType >= SIS_661) { data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07; } else if(IS_SIS550650740) { data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07; @@ -1932,6 +1961,43 @@ } /*********************************************/ +/* HELPER: ENABLE CRT1 */ +/*********************************************/ + +static void +SiS_SetupCR5x(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(IS_SIS650) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + } else if(IS_SIS661741660760) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); + if(!SiS_Pr->SiS_ROMNew) { + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); + } + } + } +} + +static void +SiS_HandleCRT1(SiS_Private *SiS_Pr) +{ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf); +#if 0 + if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { + if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || + (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { + SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40); + } + } +#endif +} + +/*********************************************/ /* HELPER: GetColorDepth */ /*********************************************/ @@ -1965,28 +2031,22 @@ SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) { - USHORT temp,colordepth,infoflag; + USHORT xres, temp, colordepth, infoflag; if(SiS_Pr->UseCustomMode) { infoflag = SiS_Pr->CInfoFlag; - temp = SiS_Pr->CHDisplay / 16; + xres = SiS_Pr->CHDisplay; } else { infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; - temp = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeOffset; - temp = SiS_Pr->SiS_ScreenOffset[temp]; + xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; } colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex); + temp = xres / 16; if(infoflag & InterlaceMode) temp <<= 1; - temp *= colordepth; - - if( ( ((ModeNo >= 0x26) && (ModeNo <= 0x28)) || - ModeNo == 0x3f || - ModeNo == 0x42 || - ModeNo == 0x45 ) || - (SiS_Pr->UseCustomMode && (SiS_Pr->CHDisplay % 16)) ) { + if(xres % 16) { colordepth >>= 1; temp += colordepth; } @@ -2091,9 +2151,15 @@ CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); /* Set CRTC(3d4) */ } - if( ( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) && - (HwInfo->jChipRevision >= 0x30) ) { /* for 630S0 */ + if(HwInfo->jChipType >= SIS_661) { + SiS_SetupCR5x(SiS_Pr, HwInfo); + for(i = 0x13; i <= 0x14; i++) { + CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; + SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata); + } + } else if( ( (HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) ) && + (HwInfo->jChipRevision >= 0x30) ) { /* for 630S0 */ if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) { SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE); @@ -2194,7 +2260,7 @@ /*********************************************/ static void -SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo) { USHORT i; @@ -2204,6 +2270,11 @@ if(HwInfo->jChipType >= SIS_315H) { SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE); + if(ModeNo <= 0x13) { + if(ModeNo == 0x06 || ModeNo >= 0x0e) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20); + } + } } } @@ -2267,45 +2338,6 @@ /* CRTC/2 */ /*********************************************/ -#ifdef SIS315H -static void -SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, USHORT *ResIndex, - USHORT *DisplayType) - { - USHORT modeflag = 0; - - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - *ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - *ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } - - *ResIndex &= 0x3F; - - *DisplayType = SiS_Pr->SiS_LCDResInfo; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 32; - if(modeflag & HalfDCLK) *DisplayType += 16; - - if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - *DisplayType = 100; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2; - if(modeflag & HalfDCLK) *DisplayType += 1; - } - } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - *DisplayType = 104; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2; - if(modeflag & HalfDCLK) *DisplayType += 1; - } - } - -} -#endif - static void SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, @@ -2313,10 +2345,6 @@ { UCHAR index; USHORT temp,i,j,modeflag; -#ifdef SIS315H - USHORT ResIndex,DisplayType; - const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL; -#endif SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /* unlock cr0-7 */ @@ -2324,7 +2352,7 @@ modeflag = SiS_Pr->CModeFlag; - for(i=0,j=0;i<=07;i++,j++) { + for(i=0,j=0;i<=7;i++,j++) { SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); } for(j=0x10;i<=10;i++,j++) { @@ -2342,7 +2370,7 @@ temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; if(modeflag & DoubleScanMode) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); } else { @@ -2352,87 +2380,28 @@ modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } - if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - -#ifdef SIS315H - - SiS_GetLCDACRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &ResIndex, &DisplayType); - - switch(DisplayType) { - case Panel_1024x768 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1; break; - case Panel_1280x1024 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1; break; - case Panel_1400x1050 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1; break; - case Panel_1600x1200 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1; break; - case Panel_1024x768 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H; break; - case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H; break; - case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H; break; - case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H; break; - case Panel_1024x768 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2; break; - case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2; break; - case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2; break; - case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2; break; - case Panel_1024x768 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H; break; - case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H; break; - case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H; break; - case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H; break; - case 100: LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1; break; - case 101: LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1_H; break; - case 102: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2; break; - case 103: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H; break; - case 104: LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1; break; - case 105: LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1_H; break; - case 106: LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2; break; - case 107: LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2_H; break; - default: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1; break; - } - - for(i=0, j=0; i<=0x07; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]); - } - for(i=0x10, j=8; i<=0x12; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]); - } - for(i=0x15, j=11; i<=0x16; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]); - } - for(i=0x0A, j=13; i<=0x0C; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_P3c4,i,(LCDACRT1Ptr+ResIndex)->CR[j]); - } + index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - temp = (LCDACRT1Ptr+ResIndex)->CR[16] & 0xE0; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); - - temp = ((LCDACRT1Ptr+ResIndex)->CR[16] & 0x01) << 5; - if(modeflag & DoubleScanMode) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp); - -#endif - - } else { - - index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - - for(i=0,j=0;i<=07;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x10;i<=10;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x15;i<=12;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for(j=0x0A;i<=15;i++,j++) { - SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); - } + for(i=0,j=0;i<=7;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x10;i<=10;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x15;i<=12;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } + for(j=0x0A;i<=15;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]); + } - temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); + temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; + SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp); - temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if(modeflag & DoubleScanMode) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp); + temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; + if(modeflag & DoubleScanMode) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp); - } } if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F); @@ -2470,7 +2439,7 @@ DisplayUnit <<= 5; temp = (DisplayUnit & 0xff00) >> 8; - if (DisplayUnit & 0xff) temp++; + if(DisplayUnit & 0xff) temp++; temp++; SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp); } @@ -2905,7 +2874,8 @@ { USHORT modeflag; - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); /* disable auto-threshold */ + /* disable auto-threshold */ + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE); if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; @@ -2913,30 +2883,19 @@ modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } - if(HwInfo->jChipType >= SIS_661) { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); - if(ModeNo > 0x13) { + SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); + if(ModeNo > 0x13) { + if(HwInfo->jChipType >= SIS_661) { if(!(modeflag & HalfDCLK)) { SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); - if(ModeNo != 0x38) { - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); - } + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); } - } - } else { - if(ModeNo > 0x13) { - if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { + } else { + if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01); - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); - } - } else { - SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0); + } } } } @@ -2951,33 +2910,29 @@ USHORT ModeNo, USHORT RefreshRateTableIndex, USHORT ModeIdIndex) { - USHORT data, data2=0; - USHORT VCLK, index=0; + USHORT data=0, VCLK=0, index=0; - if(ModeNo <= 0x13) VCLK = 0; - else { + if(ModeNo > 0x13) { if(SiS_Pr->UseCustomMode) { VCLK = SiS_Pr->CSRClock; } else { index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); + RefreshRateTableIndex,HwInfo); VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; } } - if(HwInfo->jChipType < SIS_315H) { /* 300 series */ + if(HwInfo->jChipType < SIS_315H) { - data2 = 0x00; - if(VCLK > 150) data2 |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2); + if(VCLK > 150) data |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data); - data2 = 0x00; - if(VCLK >= 150) data2 |= 0x08; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2); + data = 0x00; + if(VCLK >= 150) data |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data); - } else { /* 315 series */ + } else { - data = 0; if(VCLK >= 166) data |= 0x0c; SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data); @@ -2986,23 +2941,31 @@ } } - data2 = 0x03; - if((VCLK >= 135) && (VCLK < 160)) data2 = 0x02; - else if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01; - else if(VCLK >= 260) data2 = 0x00; + /* DAC speed */ + if(HwInfo->jChipType >= SIS_661) { - if(HwInfo->jChipType == SIS_540) { - if((VCLK == 203) || (VCLK < 234)) data2 = 0x02; - } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10); - if(HwInfo->jChipType < SIS_315H) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2); /* DAC speed */ } else { - if(HwInfo->jChipType > SIS_315PRO) { - /* This "if" is done in 330 and 650/LVDS/301LV BIOSes; Not in 315 BIOS */ - if(ModeNo > 0x13) data2 &= 0xfc; + + data = 0x03; + if((VCLK >= 135) && (VCLK < 160)) data = 0x02; + else if((VCLK >= 160) && (VCLK < 260)) data = 0x01; + else if(VCLK >= 260) data = 0x00; + + if(HwInfo->jChipType == SIS_540) { + if((VCLK == 203) || (VCLK < 234)) data = 0x02; + } + + if(HwInfo->jChipType < SIS_315H) { + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data); + } else { + if(HwInfo->jChipType > SIS_315PRO) { + if(ModeNo > 0x13) data &= 0xfc; + } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data); } - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2); /* DAC speed */ + } } @@ -3010,75 +2973,51 @@ SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex) { - USHORT data,data2; - USHORT infoflag=0,modeflag; + USHORT data,infoflag=0,modeflag; USHORT resindex,xres; #ifdef SIS315H - USHORT data3; + USHORT data2,data3; ULONG longdata; -#if 0 - resinfo = 0; -#endif + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; #endif if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; infoflag = SiS_Pr->CInfoFlag; + xres = SiS_Pr->CHDisplay; } else { + resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); if(ModeNo > 0x13) { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag; -#ifdef SIS315H -#if 0 - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; -#endif -#endif + xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; } else { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; } } /* Disable DPMS */ SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); - if(ModeNo > 0x13) data = infoflag; - else data = 0; - - data2 = 0; + data = 0; if(ModeNo > 0x13) { if(SiS_Pr->SiS_ModeType > 0x02) { - data2 |= 0x02; - data2 |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); - } - } - -#ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Debug: Mode infoflag = %x, Chiptype %d\n", - data, HwInfo->jChipType); -#endif - - if(data & InterlaceMode) data2 |= 0x20; - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data2); - - if(SiS_Pr->UseCustomMode) { - xres = SiS_Pr->CHDisplay; - } else { - resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex); - if(ModeNo <= 0x13) { - xres = SiS_Pr->SiS_StResInfo[resindex].HTotal; - } else { - xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal; + data |= 0x02; + data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); } + if(infoflag & InterlaceMode) data |= 0x20; } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data); if(HwInfo->jChipType != SIS_300) { - data = 0x0000; + data = 0; if(infoflag & InterlaceMode) { - if(xres <= 800) data = 0x0020; + if(xres <= 800) data = 0x0020; else if(xres <= 1024) data = 0x0035; - else data = 0x0048; + else data = 0x0048; } - SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0x00FF)); + SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0xFF)); SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8)); } @@ -3086,18 +3025,12 @@ SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08); } + data = 0; + if(modeflag & LineCompareOff) data = 0x08; if(HwInfo->jChipType == SIS_300) { - if(modeflag & LineCompareOff) { - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08); - } else { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7); - } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data); } else { - if(modeflag & LineCompareOff) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08); - } else { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7); - } + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data); if(SiS_Pr->SiS_ModeType == ModeEGA) { if(ModeNo > 0x13) { SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40); @@ -3105,9 +3038,13 @@ } } + if(HwInfo->jChipType >= SIS_661) { + SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb); + } + #ifdef SIS315H - /* 315 BIOS sets SR17 at this point */ if(HwInfo->jChipType == SIS_315PRO) { + data = SiS_Get310DRAMType(SiS_Pr, HwInfo); data = SiS_Pr->SiS_SR15[2][data]; if(SiS_Pr->SiS_ModeType == ModeText) { @@ -3126,12 +3063,18 @@ } } SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); - } - /* 330 BIOS sets SR17 at this point */ - if(HwInfo->jChipType == SIS_330) { + } else if( (HwInfo->jChipType == SIS_330) || + ((HwInfo->jChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760UMA))) { + data = SiS_Get310DRAMType(SiS_Pr, HwInfo); - data = SiS_Pr->SiS_SR15[2][data]; + if(HwInfo->jChipType == SIS_330) { + data = SiS_Pr->SiS_SR15[2][data]; + } else { + if(SiS_Pr->SiS_ROMNew) data = ROMAddr[0xf6]; + else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data]; + else data = 0xba; + } if(SiS_Pr->SiS_ModeType <= ModeEGA) { data &= 0xc7; } else { @@ -3144,31 +3087,38 @@ } data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1; - if(!data3) data3++; - - data2 *= data3; + if(data3) data2 *= data3; longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024; data2 = longdata / data2; - if(SiS_Pr->SiS_ModeType != Mode16Bpp) { - if(data2 >= 0x19c) data = 0xba; - else if(data2 >= 0x140) data = 0x7a; - else if(data2 >= 0x101) data = 0x3a; - else if(data2 >= 0xf5) data = 0x32; - else if(data2 >= 0xe2) data = 0x2a; - else if(data2 >= 0xc4) data = 0x22; - else if(data2 >= 0xac) data = 0x1a; - else if(data2 >= 0x9e) data = 0x12; - else if(data2 >= 0x8e) data = 0x0a; + if(HwInfo->jChipType == SIS_330) { + if(SiS_Pr->SiS_ModeType != Mode16Bpp) { + if (data2 >= 0x19c) data = 0xba; + else if(data2 >= 0x140) data = 0x7a; + else if(data2 >= 0x101) data = 0x3a; + else if(data2 >= 0xf5) data = 0x32; + else if(data2 >= 0xe2) data = 0x2a; + else if(data2 >= 0xc4) data = 0x22; + else if(data2 >= 0xac) data = 0x1a; + else if(data2 >= 0x9e) data = 0x12; + else if(data2 >= 0x8e) data = 0x0a; + else data = 0x02; + } else { + if(data2 >= 0x127) data = 0xba; + else data = 0x7a; + } + } else { + if (data2 >= 0x190) data = 0xba; + else if(data2 >= 0xff) data = 0x7a; + else if(data2 >= 0xd3) data = 0x3a; + else if(data2 >= 0xa9) data = 0x1a; + else if(data2 >= 0x93) data = 0x0a; else data = 0x02; - } else { - if(data2 >= 0x127) data = 0xba; - else data = 0x7a; - } - } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); + } + } + SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data); } #endif @@ -3190,46 +3140,6 @@ } else { SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c); } -#if 0 /* What is SR0E[D5:6]? */ - if(HwInfo->jChipType >= SIS_661) { - data = 0; - if((ModeNo == 6) || ((ModeNo >= 0x0e) && (ModeNo <= 0x13))) { - data |= 0x20; - } - if(SiS_Pr->SiS_ModeType != ModeVGA) { - if(SiS_Pr->UseCustomMode) { - if((xres >= 640) && (SiS_Pr->CVDisplay >= 480)) { - data |= 0x40; - } - if((xres > 1280) && (SiS_Pr->CVDisplay > 1024)) { - data |= 0x60; - } - } - } else if(ModeNo > 0x13) { /* These are in the CRT1 table, and set by CRT1CRTC */ - if(resinfo >= SIS_RI_640x480) { - if(resinfo <= SIS_RI_2048x1536) { - data |= 0x40; - if(resinfo > SIS_RI_1280x1024) { - data |= 0x60; - if(resinfo != SIS_RI_1600x1200) { - data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x0e); - data += 0x60; - SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e); - data = 0; - } - } - } - if(resinfo == SIS_RI_1152x864) { - data = 0x40; - } - if(resinfo == SIS_RI_1400x1050) { /* TW */ - data = 0x60; - } - } - } - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0e,data); - } -#endif } #endif } @@ -3404,7 +3314,7 @@ SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex); SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo); SiS_SetGRCRegs(SiS_Pr, StandTableIndex); - SiS_ClearExt1Regs(SiS_Pr,HwInfo); + SiS_ClearExt1Regs(SiS_Pr, HwInfo, ModeNo); SiS_ResetCRT1VCLK(SiS_Pr, HwInfo); SiS_Pr->SiS_SelectCRT2Rate = 0; @@ -3469,22 +3379,31 @@ } } + + /*********************************************/ -/* HELPER: ENABLE CRT1 */ +/* HELPER: RESET VIDEO BRIDGE */ /*********************************************/ static void -SiS_HandleCRT1(SiS_Private *SiS_Pr) +SiS_ResetVB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf); -#if 0 - if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) { - if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) || - (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40); - } - } -#endif + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT temp; + + if(SiS_Pr->SiS_UseROM) { + if(HwInfo->jChipType < SIS_330) { + temp = ROMAddr[VB310Data_1_2_Offset] | 0x40; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } else if(HwInfo->jChipType >= SIS_661) { + temp = ROMAddr[0x7e]; + if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80]; + if(HwInfo->jChipType >= SIS_660) temp |= 0x40; + else if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); + } + } } /*********************************************/ @@ -3573,13 +3492,12 @@ SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo) #endif { - ULONG temp; USHORT ModeIdIndex; - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; - unsigned char backupreg=0, tempr1, tempr2; + unsigned char backupreg=0; #ifndef LINUX_XF86 USHORT KeepLockReg; + ULONG temp; SiS_Pr->UseCustomMode = FALSE; SiS_Pr->CRT1UsesCustomMode = FALSE; @@ -3590,37 +3508,26 @@ } SiSInitPtr(SiS_Pr, HwInfo); - SiSRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr, HwInfo); -#ifdef LINUX_XF86 +#if defined(LINUX_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); else #endif SiS_Pr->SiS_VGAINFO = 0x11; SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); - if(!SiS_Pr->UseCustomMode) { - ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f); - } + SiS_Pr->SiS_flag_clearbuffer = 0; -#ifdef LINUX_XF86 - /* We never clear the buffer in X */ - ModeNo |= 0x8000; + if(!SiS_Pr->UseCustomMode) { +#ifndef LINUX_XF86 + if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1; #endif - - if(ModeNo & 0x8000) { - ModeNo &= 0x7fff; - SiS_Pr->SiS_flag_clearbuffer = 0; - } else { - SiS_Pr->SiS_flag_clearbuffer = 1; + ModeNo &= 0x7f; } #ifndef LINUX_XF86 @@ -3642,23 +3549,9 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if(HwInfo->jChipType >= SIS_315H) { - SiS_UnLockCRT2(SiS_Pr,HwInfo); - if(ROMAddr && SiS_Pr->SiS_UseROM) { - if(HwInfo->jChipType < SIS_330) { - temp = ROMAddr[VB310Data_1_2_Offset]; - temp |= 0x40; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); - } - if(HwInfo->jChipType > SIS_330) { - temp = ROMAddr[0x7e]; - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); - } - } + SiS_ResetVB(SiS_Pr, HwInfo); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); - SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); } else { backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); @@ -3679,27 +3572,7 @@ #endif if(HwInfo->jChipType >= SIS_315H) { -#if 0 - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(ModeNo != 0x10) SiS_Pr->SiS_SetFlag |= SetDOSMode; - } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) { - SiS_Pr->SiS_SetFlag |= SetDOSMode; - } - } -#endif - - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(IS_SIS650) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - } else if(IS_SIS661741660760) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); - } - } + SiS_SetupCR5x(SiS_Pr, HwInfo); } if(SiS_Pr->UseCustomMode) { @@ -3743,7 +3616,7 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if(HwInfo->jChipType >= SIS_315H) { - if(HwInfo->jChipType < SIS_661) { + if(!SiS_Pr->SiS_ROMNew) { if(SiS_IsVAMode(SiS_Pr,HwInfo)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); } else { @@ -3753,14 +3626,6 @@ SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); - tempr1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - tempr2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00); - if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7; - else tempr2 |= 0x08; - if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB; - else tempr2 |= 0x04; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,tempr2); - if((IS_SIS650) && (SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0xfc)) { if((ModeNo == 0x03) || (ModeNo == 0x10)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x80); @@ -3768,7 +3633,7 @@ } } - if(tempr1 & SetCRT2ToLCD) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); } } else if((HwInfo->jChipType == SIS_630) || @@ -3840,12 +3705,10 @@ SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, DisplayModePtr mode, BOOLEAN IsCustom) { - ULONG temp; USHORT ModeIdIndex; - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; SISIOADDRESS BaseAddr = HwInfo->ulIOAddress; UShort ModeNo = 0; - unsigned char tempr1, tempr2, backupreg=0; + unsigned char backupreg=0; SISPtr pSiS = SISPTR(pScrn); #ifdef SISDUALHEAD SISEntPtr pSiSEnt = pSiS->entityPrivate; @@ -3877,17 +3740,15 @@ } SiSRegInit(SiS_Pr, BaseAddr); - SiSInitPtr(SiS_Pr, HwInfo); - SiS_GetSysFlags(SiS_Pr, HwInfo); - +#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); - +#else + SiS_Pr->SiS_VGAINFO = 0x11; +#endif SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); /* Save mode info so we can set it from within SetMode for CRT1 */ @@ -3947,23 +3808,9 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if(HwInfo->jChipType >= SIS_315H) { - SiS_UnLockCRT2(SiS_Pr,HwInfo); - if(ROMAddr && SiS_Pr->SiS_UseROM) { - if(HwInfo->jChipType < SIS_330) { - temp = ROMAddr[VB310Data_1_2_Offset]; - temp |= 0x40; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); - } - if(HwInfo->jChipType > SIS_330) { - temp = ROMAddr[0x7e]; - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp); - } - } + SiS_ResetVB(SiS_Pr, HwInfo); SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10); - SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c); - backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); } else { backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); @@ -4005,7 +3852,7 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if(HwInfo->jChipType >= SIS_315H) { - if(HwInfo->jChipType < SIS_661) { + if(!SiS_Pr->SiS_ROMNew) { if(SiS_IsVAMode(SiS_Pr,HwInfo)) { SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01); } else { @@ -4015,15 +3862,7 @@ SiS_SetReg(SiS_Pr->SiS_P3d4,0x38,backupreg); - tempr1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); - tempr2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00); - if(tempr1 & SetCRT2ToAVIDEO) tempr2 &= 0xF7; - else tempr2 |= 0x08; - if(tempr1 & SetCRT2ToSVIDEO) tempr2 &= 0xFB; - else tempr2 |= 0x04; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,tempr2); - - if(tempr1 & SetCRT2ToLCD) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) { SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc); } } else if((HwInfo->jChipType == SIS_630) || @@ -4081,17 +3920,15 @@ } SiSInitPtr(SiS_Pr, HwInfo); - SiSRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr, HwInfo); - +#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__)) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff); - +#else + SiS_Pr->SiS_VGAINFO = 0x11; +#endif SiSInitPCIetc(SiS_Pr, HwInfo); - SiSSetLVDSetc(SiS_Pr, HwInfo); - SiSDetermineROMUsage(SiS_Pr, HwInfo); /* We don't clear the buffer under X */ @@ -4127,27 +3964,7 @@ SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo); if(HwInfo->jChipType >= SIS_315H) { -#if 0 - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(ModeNo != 0x10) SiS_Pr->SiS_SetFlag |= SetDOSMode; - } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) { - SiS_Pr->SiS_SetFlag |= SetDOSMode; - } - } -#endif - - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if(IS_SIS650) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - } else if(IS_SIS661741660760) { - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7); - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef); - } - } + SiS_SetupCR5x(SiS_Pr, HwInfo); } /* Set mode on CRT1 */ @@ -4316,12 +4133,188 @@ } #endif +#ifndef GETBITSTR +#define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) +#define GENMASK(mask) BITMASK(1?mask,0?mask) +#define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) +#define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) +#endif + +static void +SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth) +{ + SiS_Pr->CCRT1CRTC[0] = ((SiS_Pr->CHTotal >> 3) - 5) & 0xff; /* CR0 */ + SiS_Pr->CCRT1CRTC[1] = (SiS_Pr->CHDisplay >> 3) - 1; /* CR1 */ + SiS_Pr->CCRT1CRTC[2] = (SiS_Pr->CHBlankStart >> 3) - 1; /* CR2 */ + SiS_Pr->CCRT1CRTC[3] = (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80; /* CR3 */ + SiS_Pr->CCRT1CRTC[4] = (SiS_Pr->CHSyncStart >> 3) + 3; /* CR4 */ + SiS_Pr->CCRT1CRTC[5] = ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | /* CR5 */ + (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); + + SiS_Pr->CCRT1CRTC[6] = (SiS_Pr->CVTotal - 2) & 0xFF; /* CR6 */ + SiS_Pr->CCRT1CRTC[7] = (((SiS_Pr->CVTotal - 2) & 0x100) >> 8) /* CR7 */ + | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7) + | ((SiS_Pr->CVSyncStart & 0x100) >> 6) + | (((SiS_Pr->CVBlankStart - 1) & 0x100) >> 5) + | 0x10 + | (((SiS_Pr->CVTotal - 2) & 0x200) >> 4) + | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3) + | ((SiS_Pr->CVSyncStart & 0x200) >> 2); + + SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); /* CR9 */ + + if(depth != 8) { + if(SiS_Pr->CHDisplay >= 1600) SiS_Pr->CCRT1CRTC[16] |= 0x60; /* SRE */ + else if(SiS_Pr->CHDisplay >= 640) SiS_Pr->CCRT1CRTC[16] |= 0x40; + } + +#if 0 + if (mode->VScan >= 32) + regp->CRTC[9] |= 0x1F; + else if (mode->VScan > 1) + regp->CRTC[9] |= mode->VScan - 1; +#endif + + SiS_Pr->CCRT1CRTC[8] = (SiS_Pr->CVSyncStart ) & 0xFF; /* CR10 */ + SiS_Pr->CCRT1CRTC[9] = ((SiS_Pr->CVSyncEnd ) & 0x0F) | 0x80; /* CR11 */ + SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay - 1) & 0xFF; /* CR12 */ + SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF; /* CR15 */ + SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd - 1) & 0xFF; /* CR16 */ + + SiS_Pr->CCRT1CRTC[13] = /* SRA */ + GETBITSTR((SiS_Pr->CVTotal -2), 10:10, 0:0) | + GETBITSTR((SiS_Pr->CVDisplay -1), 10:10, 1:1) | + GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) | + GETBITSTR((SiS_Pr->CVSyncStart ), 10:10, 3:3) | + GETBITSTR((SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | + GETBITSTR((SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; + + SiS_Pr->CCRT1CRTC[14] = /* SRB */ + GETBITSTR((SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | + GETBITSTR((SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | + GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | + GETBITSTR((SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; + + + SiS_Pr->CCRT1CRTC[15] = /* SRC */ + GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | + GETBITSTR((SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; +} + +void +SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) +{ + USHORT modeflag, tempax, tempbx, VGAHDE = SiS_Pr->SiS_VGAHDE; + int i,j; + + /* 1:1 data: use data set by setcrt1crtc() */ + if(SiS_Pr->SiS_LCDInfo & LCDPass11) return; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + } else { + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + } + + if(modeflag & HalfDCLK) VGAHDE >>= 1; + + SiS_Pr->CHDisplay = VGAHDE; + SiS_Pr->CHBlankStart = VGAHDE; + + SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE; + SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE; + + tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes; + tempax = SiS_Pr->SiS_VGAHDE; /* not /2 ! */ + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelXRes; + } + tempbx += tempax; + if(modeflag & HalfDCLK) tempbx -= VGAHDE; + SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx; + + tempax = VGAHDE; + tempbx = SiS_Pr->CHTotal; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempbx = SiS_Pr->PanelXRes; + if(modeflag & HalfDCLK) tempbx >>= 1; + tempax += ((tempbx - tempax) >> 1); + } + + tempax += SiS_Pr->PanelHRS; + SiS_Pr->CHSyncStart = tempax; + tempax += SiS_Pr->PanelHRE; + SiS_Pr->CHSyncEnd = tempax; + + tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes; + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax = SiS_Pr->PanelYRes; + } + SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax; + + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempax += (SiS_Pr->PanelYRes - tempax) >> 1; + } + tempax += SiS_Pr->PanelVRS; + SiS_Pr->CVSyncStart = tempax; + tempax += SiS_Pr->PanelVRE; + SiS_Pr->CVSyncEnd = tempax; + + SiS_CalcCRRegisters(SiS_Pr, 8); + SiS_Pr->CCRT1CRTC[16] &= ~0xE0; + + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); + + for(i=0,j=0;i<=7;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x10;i<=10;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x15;i<=12;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]); + } + for(j=0x0A;i<=15;i++,j++) { + SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]); + } + + tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax); + + tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5; + if(modeflag & DoubleScanMode) tempax |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax); + +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "%d %d %d %d %d %d %d %d (%d %d %d %d)\n", + SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal, + SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal, + SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd); + + xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1], + SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3], + SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5], + SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]); + xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", + SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9], + SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11], + SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13], + SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]); + xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]); +#endif +} /* ================ XFREE86 ================= */ /* Helper functions */ #ifdef LINUX_XF86 + USHORT SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags) { @@ -4402,73 +4395,16 @@ pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1; - pSiS->SiS_Pr->CCRT1CRTC[0] = ((pSiS->SiS_Pr->CHTotal >> 3) - 5) & 0xff; - pSiS->SiS_Pr->CCRT1CRTC[1] = (pSiS->SiS_Pr->CHDisplay >> 3) - 1; - pSiS->SiS_Pr->CCRT1CRTC[2] = (pSiS->SiS_Pr->CHBlankStart >> 3) - 1; - pSiS->SiS_Pr->CCRT1CRTC[3] = (((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80; - pSiS->SiS_Pr->CCRT1CRTC[4] = (pSiS->SiS_Pr->CHSyncStart >> 3) + 3; - pSiS->SiS_Pr->CCRT1CRTC[5] = ((((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) | - (((pSiS->SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F); - - pSiS->SiS_Pr->CCRT1CRTC[6] = (pSiS->SiS_Pr->CVTotal - 2) & 0xFF; - pSiS->SiS_Pr->CCRT1CRTC[7] = (((pSiS->SiS_Pr->CVTotal - 2) & 0x100) >> 8) - | (((pSiS->SiS_Pr->CVDisplay - 1) & 0x100) >> 7) - | ((pSiS->SiS_Pr->CVSyncStart & 0x100) >> 6) - | (((pSiS->SiS_Pr->CVBlankStart - 1) & 0x100) >> 5) - | 0x10 - | (((pSiS->SiS_Pr->CVTotal - 2) & 0x200) >> 4) - | (((pSiS->SiS_Pr->CVDisplay - 1) & 0x200) >> 3) - | ((pSiS->SiS_Pr->CVSyncStart & 0x200) >> 2); - - pSiS->SiS_Pr->CCRT1CRTC[16] = ((((pSiS->SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); /* cr9 */ - -#if 0 - if (mode->VScan >= 32) - regp->CRTC[9] |= 0x1F; - else if (mode->VScan > 1) - regp->CRTC[9] |= mode->VScan - 1; -#endif - - pSiS->SiS_Pr->CCRT1CRTC[8] = (pSiS->SiS_Pr->CVSyncStart ) & 0xFF; /* cr10 */ - pSiS->SiS_Pr->CCRT1CRTC[9] = ((pSiS->SiS_Pr->CVSyncEnd ) & 0x0F) | 0x80; /* cr11 */ - pSiS->SiS_Pr->CCRT1CRTC[10] = (pSiS->SiS_Pr->CVDisplay - 1) & 0xFF; /* cr12 */ - pSiS->SiS_Pr->CCRT1CRTC[11] = (pSiS->SiS_Pr->CVBlankStart - 1) & 0xFF; /* cr15 */ - pSiS->SiS_Pr->CCRT1CRTC[12] = (pSiS->SiS_Pr->CVBlankEnd - 1) & 0xFF; /* cr16 */ - - pSiS->SiS_Pr->CCRT1CRTC[13] = - GETBITSTR((pSiS->SiS_Pr->CVTotal -2), 10:10, 0:0) | - GETBITSTR((pSiS->SiS_Pr->CVDisplay -1), 10:10, 1:1) | - GETBITSTR((pSiS->SiS_Pr->CVBlankStart-1), 10:10, 2:2) | - GETBITSTR((pSiS->SiS_Pr->CVSyncStart ), 10:10, 3:3) | - GETBITSTR((pSiS->SiS_Pr->CVBlankEnd -1), 8:8, 4:4) | - GETBITSTR((pSiS->SiS_Pr->CVSyncEnd ), 4:4, 5:5) ; - - pSiS->SiS_Pr->CCRT1CRTC[14] = - GETBITSTR((pSiS->SiS_Pr->CHTotal >> 3) - 5, 9:8, 1:0) | - GETBITSTR((pSiS->SiS_Pr->CHDisplay >> 3) - 1, 9:8, 3:2) | - GETBITSTR((pSiS->SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) | - GETBITSTR((pSiS->SiS_Pr->CHSyncStart >> 3) + 3, 9:8, 7:6) ; - - - pSiS->SiS_Pr->CCRT1CRTC[15] = - GETBITSTR((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) | - GETBITSTR((pSiS->SiS_Pr->CHSyncEnd >> 3) + 3, 5:5, 2:2) ; + SiS_CalcCRRegisters(pSiS->SiS_Pr, depth); switch(depth) { - case 8: - pSiS->SiS_Pr->CModeFlag |= 0x223b; - break; - case 16: - pSiS->SiS_Pr->CModeFlag |= 0x227d; - break; - case 32: - pSiS->SiS_Pr->CModeFlag |= 0x22ff; - break; - default: - return 0; - } - - if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) + case 8: pSiS->SiS_Pr->CModeFlag |= 0x223b; break; + case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break; + case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break; + default: return 0; + } + + if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) pSiS->SiS_Pr->CModeFlag |= DoubleScanMode; if((pSiS->SiS_Pr->CVDisplay >= 1024) || @@ -4492,33 +4428,23 @@ pSiS->SiS_Pr->UseCustomMode = TRUE; #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n", + xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n", pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay); xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n", pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag); xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - pSiS->SiS_Pr->CCRT1CRTC[0], - pSiS->SiS_Pr->CCRT1CRTC[1], - pSiS->SiS_Pr->CCRT1CRTC[2], - pSiS->SiS_Pr->CCRT1CRTC[3], - pSiS->SiS_Pr->CCRT1CRTC[4], - pSiS->SiS_Pr->CCRT1CRTC[5], - pSiS->SiS_Pr->CCRT1CRTC[6], - pSiS->SiS_Pr->CCRT1CRTC[7]); + pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1], + pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3], + pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5], + pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]); xf86DrvMsg(0, X_INFO, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n", - pSiS->SiS_Pr->CCRT1CRTC[8], - pSiS->SiS_Pr->CCRT1CRTC[9], - pSiS->SiS_Pr->CCRT1CRTC[10], - pSiS->SiS_Pr->CCRT1CRTC[11], - pSiS->SiS_Pr->CCRT1CRTC[12], - pSiS->SiS_Pr->CCRT1CRTC[13], - pSiS->SiS_Pr->CCRT1CRTC[14], - pSiS->SiS_Pr->CCRT1CRTC[15]); + pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9], + pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11], + pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13], + pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]); xf86DrvMsg(0, X_INFO, " 0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]); xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n", - pSiS->SiS_Pr->CSR2B, - pSiS->SiS_Pr->CSR2C, - pSiS->SiS_Pr->CSRClock); + pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock); #endif return 1; } @@ -4635,7 +4561,7 @@ /* Horizontal display enable end */ HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6); - E = HDE + 1; + E = HDE + 1; /* 0x80 0x64 */ cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[4]; /* inSISIDXREG(SISCR, 0x04, cr_data); */ @@ -4643,7 +4569,7 @@ /* Horizontal retrace (=sync) start */ HRS = (cr_data & 0xff) | ((unsigned short) (sr_data & 0xC0) << 2); - F = HRS - E - 3; + F = HRS - E - 3; /* 0x06 0x06 */ cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[2]; /* inSISIDXREG(SISCR, 0x02, cr_data); */ @@ -4673,7 +4599,7 @@ B = (temp > 0) ? temp : (temp + 256); temp = HRE - ((E + F + 3) & 63); - C = (temp > 0) ? temp : (temp + 64); + C = (temp > 0) ? temp : (temp + 64); /* 0x0b 0x0b */ D = B - F - C; @@ -5205,7 +5131,7 @@ return 0; #endif } - + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0; RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; diff -urN linux-2.4.25/drivers/video/sis/init.h linux-2.4.26/drivers/video/sis/init.h --- linux-2.4.25/drivers/video/sis/init.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/init.h 2004-04-14 06:05:39.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -111,9 +108,11 @@ const USHORT ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b}; const USHORT ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25}; const USHORT ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78}; +const USHORT ModeIndex_1280x800[] = {0x14, 0x15, 0x00, 0x16}; const USHORT ModeIndex_1360x768[] = {0x48, 0x4b, 0x00, 0x4e}; const USHORT ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72}; /* 300 series, BARCO only */ const USHORT ModeIndex_1400x1050[] = {0x26, 0x27, 0x00, 0x28}; /* 315 series only */ +const USHORT ModeIndex_1680x1050[] = {0x17, 0x18, 0x00, 0x19}; /* 315 series only */ const USHORT ModeIndex_1600x1200[] = {0x3c, 0x3d, 0x00, 0x66}; const USHORT ModeIndex_1920x1440[] = {0x68, 0x69, 0x00, 0x6b}; const USHORT ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00}; @@ -253,7 +252,9 @@ { 1024, 600, 8,16}, /* 0x19 */ { 1152, 768, 8,16}, /* 0x1a */ { 768, 576, 8,16}, /* 0x1b */ - { 1360,1024, 8,16} /* 0x1c */ + { 1360,1024, 8,16}, /* 0x1c */ + { 1280, 800, 8,16}, /* 0x1d */ + { 1680,1050, 8,16} /* 0x1e */ }; static SiS_StandTableStruct SiS_StandTable[]= @@ -758,6 +759,7 @@ 0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00 }; +#if 0 static const UCHAR SiS_HiTVTextTiming[] = { 0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65, 0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d, @@ -768,6 +770,7 @@ 0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96, 0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00 }; +#endif static const UCHAR SiS_HiTVGroup3Data[] = { 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f, @@ -791,6 +794,7 @@ 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 }; +#if 0 static const UCHAR SiS_HiTVGroup3Text[] = { 0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7, 0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6, @@ -801,6 +805,7 @@ 0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75, 0x18,0x05,0x18,0x05,0x4c,0xa8,0x01 }; +#endif static const UCHAR SiS_NTSCPhase[] = {0x21,0xed,0xba,0x08}; static const UCHAR SiS_PALPhase[] = {0x2a,0x05,0xe3,0x00}; @@ -814,7 +819,7 @@ static const UCHAR SiS_SpecialPhaseM[]= {0x1e,0x83,0x0a,0xe0}; static const UCHAR SiS_SpecialPhaseJ[]= {0x25,0xd4,0xfd,0x5e}; -static const SiS_TVDataStruct SiS_StPALData[]= +static const SiS_TVDataStruct SiS_StPALData[] = { { 1, 1, 864, 525,1270, 400, 100, 0, 760,0xf4,0xff,0x1c,0x22}, { 1, 1, 864, 525,1270, 350, 100, 0, 760,0xf4,0xff,0x1c,0x22}, @@ -838,7 +843,7 @@ { 1, 1,1170, 821,1270, 520, 686, 0, 686,0xF3,0x00,0x1D,0x20} /* 1024x768 (for NTSC equ) */ }; -static const SiS_TVDataStruct SiS_StNTSCData[]= +static const SiS_TVDataStruct SiS_StNTSCData[] = { { 1, 1, 858, 525,1270, 400, 50, 0, 760,0xf1,0x04,0x1f,0x18}, { 1, 1, 858, 525,1270, 350, 50, 0, 640,0xf1,0x04,0x1f,0x18}, @@ -847,7 +852,7 @@ { 1, 1, 858, 525,1270, 480, 0, 0, 760,0xf1,0x04,0x1f,0x18} }; -static const SiS_TVDataStruct SiS_ExtNTSCData[]= +static const SiS_TVDataStruct SiS_ExtNTSCData[] = { { 143, 65, 858, 443,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, /* 640x400, 320x200 */ { 88, 35, 858, 393,1270, 440, 171, 0, 171,0xf1,0x04,0x1f,0x18}, @@ -855,39 +860,49 @@ { 143, 70, 924, 393,1270, 440, 92, 0, 92,0xf4,0x0b,0x1c,0x0a}, { 143, 76, 836, 523,1270, 440, 224, 0, 0,0xf1,0x05,0x1f,0x16}, /* 640x480, 320x240 */ { 143, 120,1056, 643,1270, 440, 0, 128, 0,0xf4,0x10,0x1c,0x00}, /* 800x600, 400x300 */ - { 143, 76, 836, 523,1270, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ /*{ 2, 1, 858, 503,1270, 480, 0, 128, 0,0xee,0x0c,0x22,0x08},*/ /* 720x480 (old, from 650) */ - { 1, 1,1100, 811,1412, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ + { 143, 76, 836, 523,1270, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 720x480 - BETTER (from 300 series) */ /*{ 65, 64,1056, 791,1270, 480, 638, 0, 0,0xEE,0x0C,0x22,0x08} */ /* 1024x768 (525i) */ + { 1, 1,1100, 811,1412, 440, 0, 128, 0,0xee,0x0c,0x22,0x08}, /* 1024x768 (525i) CORRECTED */ { 65, 64,1056, 791,1270, 480, 455, 0, 0,0x00,0x00,0x00,0x00} /* 1024x768 (525p) */ }; -static const SiS_TVDataStruct SiS_St2HiTVData[]= +static const SiS_TVDataStruct SiS_StHiTVData[] = /* Slave + TVSimu */ +{ + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x320, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x150,128, 0, 0x00,0x00,0x00,0x00} +}; + +static const SiS_TVDataStruct SiS_St2HiTVData[] = /* Slave */ { { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, { 3, 1, 0x348,0x1e3,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, - { 1, 1, 0x3e8,0x233,0x311,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 1, 1, 0x37c,0x233,0x2b2,0x2bc, 0, 0, 0, 0x00,0x00,0x00,0x00}, { 5, 2, 0x348,0x233,0x670,0x3c0,0x08d,128, 0, 0x00,0x00,0x00,0x00}, { 8, 5, 0x41a,0x2ab,0x670,0x3c0,0x17c,128, 0, 0x00,0x00,0x00,0x00} }; -static const SiS_TVDataStruct SiS_ExtHiTVData[]= +static const SiS_TVDataStruct SiS_ExtHiTVData[] = { { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, - { 3, 1, 0x348,0x1e3,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, + { 6, 1, 0x348,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, { 3, 1, 0x3c0,0x233,0x660,0x3c0, 0, 0, 0, 0x00,0x00,0x00,0x00}, { 5, 1, 0x348,0x233,0x670,0x3c0,0x166,128, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ { 16, 5, 0x41a,0x2ab,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ { 25, 12, 0x4ec,0x353,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ { 5, 4, 0x627,0x464,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00}, /* 1280x1024 */ - { 4, 1, 0x41a,0x233,0x670,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x480 */ + { 4, 1, 0x41a,0x233,0x60c,0x3c0,0x143,128, 0, 0x00,0x00,0x00,0x00}, /* 800x480 */ { 5, 2, 0x578,0x293,0x670,0x3c0,0x032, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x576 */ { 8, 5, 0x6d6,0x323,0x670,0x3c0,0x128, 0, 0, 0x00,0x00,0x00,0x00} /* 1280x720 */ }; -static const SiS_TVDataStruct SiS_St525pData[]= +static const SiS_TVDataStruct SiS_St525pData[] = { { 1, 1, 0x6b4,0x20d,0x4f6,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, { 1, 1, 0x6b4,0x20d,0x4f6,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, @@ -896,7 +911,7 @@ { 1, 1, 0x6b4,0x20d,0x4f6,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} }; -static const SiS_TVDataStruct SiS_St750pData[]= +static const SiS_TVDataStruct SiS_St750pData[] = { { 1, 1, 0x672,0x2ee,0x500,0x190, 50, 0, 0x2f8, 0x00,0x00,0x00,0x00}, { 1, 1, 0x672,0x2ee,0x500,0x15e, 50, 0, 0x280, 0x00,0x00,0x00,0x00}, @@ -905,8 +920,21 @@ { 1, 1, 0x672,0x2ee,0x500,0x1e0, 0, 0, 0x2f8, 0x00,0x00,0x00,0x00} }; -static const SiS_TVDataStruct SiS_Ext750pData[]= +static const SiS_TVDataStruct SiS_Ext750pData[] = { +#if 1 + { 143, 65, 0x35a,0x1bb,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, + { 88, 35, 0x35a,0x189,0x4f6,0x1b8,0x0ab, 0, 0x0ab, 0x00,0x00,0x00,0x00}, + { 18, 5, 0x339,0x1ae,0x500,0x2d0,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, + { 143, 70, 0x39c,0x189,0x4f6,0x1b8,0x05c, 0, 0x05c, 0x00,0x00,0x00,0x00}, + { 99, 32, 0x320,0x1fe,0x500,0x2d0, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ + { 5, 4, 0x5d8,0x29e,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ + { 2, 1, 0x35a,0x1f7,0x4f6,0x1e0, 0,128, 0, 0x00,0x00,0x00,0x00}, /* 720x480 */ + { 68, 64, 0x55f,0x346,0x500,0x2a8,0x27e, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ + { 5, 2, 0x3a7,0x226,0x500,0x2a8, 0,128, 0, 0x00,0x00,0x00,0x00}, /* 720x576 */ + { 25, 24, 0x5d8,0x2f3,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00} /* 1280x720 */ +#endif +#if 0 { 3, 1, 0x3a7,0x1d6,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, { 24, 7, 0x3a7,0x1a4,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, { 3, 1, 0x3a7,0x1d6,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, @@ -915,63 +943,105 @@ { 5, 4, 0x5d8,0x29e,0x500,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ { 2, 1, 0x35a,0x1f7,0x4f6,0x1e0, 0,128, 0, 0x00,0x00,0x00,0x00}, /* 720x480 */ { 68, 64, 0x55f,0x346,0x500,0x2a8,0x27e, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ + { 25, 24, 0x5d8,0x2f3,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00} /* 1280x720 */ +#endif +#if 0 + { 136, 35, 0x339,0x181,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* TEST (0.93) */ + { 17, 6, 0x339,0x203,0x460,0x2a8, 50, 0, 50, 0x00,0x00,0x00,0x00}, + { 136, 35, 0x339,0x181,0x460,0x2a8, 50, 0, 50, 0x00,0x00,0x00,0x00}, + { 17, 6, 0x339,0x203,0x460,0x2a8, 50, 0, 50, 0x00,0x00,0x00,0x00}, + { 85, 46, 0x3f4,0x27b,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 640x480 */ + { 17, 16, 0x55f,0x323,0x460,0x2a8,0x2b6, 0, 0, 0x00,0x00,0x00,0x00}, /* 800x600 */ + { 136, 35, 0x339,0x181,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 720x480 */ + { 187, 74, 0x39d,0x203,0x460,0x2a8, 50, 0, 0, 0x00,0x00,0x00,0x00}, /* 1024x768 */ + { 25, 24, 0x5d8,0x2f3,0x460,0x2a8, 50, 0, 50, 0x00,0x00,0x00,0x00} /* 1280x720 */ +#endif }; -static const SiS_LCDDataStruct SiS_LCD1280x960Data[] = +static const SiS_LCDDataStruct SiS_LCD1280x720Data[] = { - { 9, 2, 800, 500,1800,1000}, - { 9, 2, 800, 500,1800,1000}, - { 4, 1, 900, 500,1800,1000}, - { 4, 1, 900, 500,1800,1000}, - { 9, 2, 800, 500,1800,1000}, - { 30, 11,1056, 625,1800,1000}, - { 5, 3,1350, 800,1800,1000}, - { 1, 1,1576,1050,1576,1050}, - { 1, 1,1800,1000,1800,1000} -}; - -/* 1280x768 panel data from Fujitsu 7911 (VL-17WDX8). - * Other 1280x768 panels (with clock != 81000, HTxVT != 1688x802) - * will be treated as custom panels. + { 14, 5, 864, 432, 1344, 806 }, /* 640x400 */ + { 16, 5, 864, 378, 1344, 806 }, + { 14, 5, 864, 432, 1344, 806 }, + { 16, 5, 864, 378, 1344, 806 }, + { 24, 11, 924, 523, 1344, 806 }, /* 640x480 */ + { 7, 5, 1152, 664, 1344, 806 }, /* 800x600 */ + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1344, 806, 1344, 806 } /* 1280x720 */ +}; + +/* About 1280x768: For TMDS, Panel_1280x768 will only be set if + * the panel is a Fujitsu 7911 (VL-17WDX8) (with clock 81, 1688x802) + * Other TMDS panels of this resolution will be treated as custom. + * For LVDS, we know two types. Data follows: */ -static const SiS_LCDDataStruct SiS_StLCD1280x768Data[] = +static const SiS_LCDDataStruct SiS_StLCD1280x768_2Data[] = { - { 211, 100, 2100, 408, 1688, 802 }, /* These values are *wrong* */ - { 211, 64, 1536, 358, 1688, 802 }, /* (which is why they aren't used yet) */ - { 211, 100, 2100, 408, 1688, 802 }, - { 211, 64, 1536, 358, 1688, 802 }, - { 211, 48, 840, 488, 1688, 802 }, - { 211, 72, 1008, 609, 1688, 802 }, - { 211, 128, 1400, 776, 1688, 802 }, - { 211, 205, 1680, 1041, 1688, 802 }, - { 1, 1, 1688, 802, 1688, 802 } /* That's the only one that is correct */ -}; - -static const SiS_LCDDataStruct SiS_ExtLCD1280x768Data[] = -{ - { 211, 100, 2100, 408, 1688, 802 }, /* These values are *wrong* */ - { 211, 64, 1536, 358, 1688, 802 }, /* (which is why they aren't used yet) */ - { 211, 100, 2100, 408, 1688, 802 }, - { 211, 64, 1536, 358, 1688, 802 }, - { 211, 48, 840, 488, 1688, 802 }, - { 211, 72, 1008, 609, 1688, 802 }, - { 211, 128, 1400, 776, 1688, 802 }, - { 211, 205, 1680, 1041, 1688, 802 }, - { 1, 1, 1688, 802, 1688, 802 } /* That's the only one that is correct */ -}; - -static const SiS_LCDDataStruct SiS_NoScaleData1280x768[] = -{ - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802}, - { 1, 1, 1688, 802, 1688, 802} + { 64, 21, 858, 434, 1408, 806 }, /* 640x400 */ + { 32, 9, 858, 372, 1408, 806 }, + { 64, 21, 858, 434, 1408, 806 }, + { 32, 9, 858, 372, 1408, 806 }, + { 143, 68, 1024, 527, 1408, 806 }, /* 640x480 */ + { 64, 51, 1364, 663, 1408, 806 }, /* 800x600 */ + { 88, 81, 1296, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 } /* 1280x768 */ +}; + +static const SiS_LCDDataStruct SiS_ExtLCD1280x768_2Data[] = +{ + { 64, 25, 1056, 422, 1408, 806 }, /*, 664 */ + { 128, 39, 884, 396, 1408, 806 }, /*, 640 */ + { 64, 25, 1056, 422, 1408, 806 }, /*, 664 */ + { 128, 39, 884, 396, 1408, 806 }, /*, 640 */ + { 32, 15, 1056, 513, 1408, 806 }, /*, 664 */ + { 176, 125, 1280, 640, 1408, 806 }, /*, 768 */ + { 88, 81, 1296, 806, 1408, 806 }, + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 } +}; + +static const SiS_LCDDataStruct SiS_LCD1280x768_3Data[] = +{ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 64, 25, 1056, 422, 1664, 798 }, /* 640x400 */ + { 128, 39, 884, 396, 1408, 806 }, /* ,640 */ + { 32, 15, 1056, 513, 1408, 806 }, /* ,664 */ /* 640x480 */ + { 176, 125, 1280, 640, 1408, 806 }, /* ,768 */ /* 800x600 */ + { 64, 61, 1342, 806, 1408, 806 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 806, 1408, 806 } /* 1280x768 */ +}; + +static const SiS_LCDDataStruct SiS_LCD1280x800Data[] = +{ + { 128, 51, 1122, 412, 1408, 816 }, /* 640x400 */ + { 128, 49, 1232, 361, 1408, 816 }, + { 128, 51, 1122, 412, 1408, 816 }, + { 128, 49, 1232, 361, 1408, 816 }, + { 8, 3, 880, 491, 1408, 816 }, /* 640x480 */ + { 11, 6, 1024, 612, 1408, 816 }, /* 800x600 */ + { 22, 21, 1400, 784, 1408, 816 }, /* 1024x768 */ + { 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1408, 816, 1408, 816 } /* 1280x800 */ +}; + +static const SiS_LCDDataStruct SiS_LCD1280x960Data[] = +{ + { 9, 2, 800, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 4, 1, 900, 500, 1800, 1000 }, + { 9, 2, 800, 500, 1800, 1000 }, + { 30, 11, 1056, 625, 1800, 1000 }, + { 5, 3, 1350, 800, 1800, 1000 }, + { 1, 1, 1576, 1050, 1576, 1050 }, + { 1, 1, 1800, 1000, 1800, 1000 } }; static const SiS_LCDDataStruct SiS_StLCD1400x1050Data[] = @@ -989,28 +1059,32 @@ static const SiS_LCDDataStruct SiS_ExtLCD1400x1050Data[] = { - { 211, 100, 2100, 408, 1688, 1066 }, + { 211, 100, 2100, 408, 1688, 1066 }, /* 640x400 */ { 211, 64, 1536, 358, 1688, 1066 }, { 211, 100, 2100, 408, 1688, 1066 }, { 211, 64, 1536, 358, 1688, 1066 }, - { 211, 48, 840, 488, 1688, 1066 }, - { 211, 72, 1008, 609, 1688, 1066 }, + { 211, 48, 840, 488, 1688, 1066 }, /* 640x480 */ + { 211, 72, 1008, 609, 1688, 1066 }, /* 800x600 */ { 211, 128, 1400, 776, 1688, 1066 }, { 211, 205, 1680, 1041, 1688, 1066 }, { 1, 1, 1688, 1066, 1688, 1066 } }; -static const SiS_LCDDataStruct SiS_NoScaleData1400x1050[] = +static const SiS_LCDDataStruct SiS_LCD1680x1050Data[] = { - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 }, - { 1, 1, 1688, 1066, 1688, 1066 } + { 95, 24, 1260, 410, 1900, 1066 }, /* 0 640x400 */ + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 24, 1260, 410, 1900, 1066 }, + { 10, 3, 1710, 362, 1900, 1066 }, + { 95, 32, 1400, 490, 1900, 1066 }, /* 4 640x480 */ + { 95, 42, 1470, 610, 1900, 1066 }, /* 5 800x600 */ + { 95, 64, 1750, 784, 1900, 1066 }, /* 6 1024x768 */ + { 95, 94, 1900, 1055, 1900, 1066 }, /* 7 1280x1024 */ + { 41, 31, 1900, 806, 1900, 1066 }, /* 8 1280x768 */ + { 95, 69, 1800, 817, 1900, 1066 }, /* 9 1280x800 patch */ + { 13, 9, 1900, 739, 1900, 1066 }, /* 10 1280x720 */ + { 95, 94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch */ + { 1, 1, 1900, 1066, 1900, 1066 } /* 12 1680x1050 */ }; static const SiS_LCDDataStruct SiS_StLCD1600x1200Data[] = @@ -1041,422 +1115,29 @@ { 1, 1,2160,1250, 2160, 1250 } }; -static const SiS_LCDDataStruct SiS_NoScaleData1600x1200[] = -{ - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, - {1, 1, 2160, 1250, 2048, 1250}, -}; - static const SiS_LCDDataStruct SiS_NoScaleData[] = { - { 1, 1, 800, 449, 800, 449 }, + { 1, 1, 800, 449, 800, 449 }, /* 0x00: 320x200, 640x400 */ { 1, 1, 800, 449, 800, 449 }, { 1, 1, 900, 449, 900, 449 }, { 1, 1, 900, 449, 900, 449 }, - { 1, 1, 800, 525, 800, 525 }, - { 1, 1,1056, 628,1056, 628 }, - { 1, 1,1344, 806,1344, 806 }, - { 1, 1,1688,1066,1688,1066 }, - { 1, 1,1688, 802,1688, 802 }, /* 1280x768: 802 was 806 in both cases */ - { 1, 1,2160,1250,2160,1250 }, /* 1600x1200 */ - { 1, 1,1800,1000,1800,1000 } /* 1280x960 */ -}; - -/* *** LCDA *** */ - -static const SiS_LVDSDataStruct SiS_LCDA1024x768Data_1[]= -{ - { 960, 438,1344, 806}, - { 960, 388,1344, 806}, - { 1040, 438,1344, 806}, - { 1040, 388,1344, 806}, - { 960, 518,1344, 806}, /* 640x480 */ - { 1120, 638,1344, 806}, /* 800x600 */ - { 1344, 806,1344, 806}, /* 1024x768 */ -#if 0 - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 438,1344, 806}, - { 840, 409,1344, 806}, - { 840, 518,1344, 806}, /* 640x480 */ - {1050, 638,1344, 806}, /* 800x600 */ - {1344, 806,1344, 806}, /* 1024x768 */ -#endif -}; - -static const SiS_LVDSDataStruct SiS_LCDA1024x768Data_2[]= -{ - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - {1344, 806,1344, 806}, -}; - -static const SiS_LVDSDataStruct SiS_LCDA1280x1024Data_1[]= -{ /* Acer, Compaq */ - {1048, 442,1688,1066}, - {1048, 392,1688,1066}, - {1128, 442,1688,1066}, - {1128, 392,1688,1066}, - {1048, 522,1688,1066}, - {1208, 642,1688,1066}, - {1432, 810,1688,1066}, - {1688,1066,1688,1066} + { 1, 1, 800, 525, 800, 525 }, /* 0x04: 320x240, 640x480 */ + { 1, 1,1056, 628,1056, 628 }, /* 0x05: 400x300, 800x600 */ + { 1, 1,1344, 806,1344, 806 }, /* 0x06: 512x384, 1024x768 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x07: 1280x1024 */ + { 1, 1,1688, 802,1688, 802 }, /* 0x08: 1280x768: Fujitsu, TMDS only */ + { 1, 1,2160,1250,2160,1250 }, /* 0x09: 1600x1200 */ + { 1, 1,1800,1000,1800,1000 }, /* 0x0a: 1280x960 */ + { 1, 1,1688,1066,1688,1066 }, /* 0x0b: 1400x1050 */ + { 1, 1,1650, 750,1650, 750 }, /* 0x0c: 1280x720 (TMDS) */ + { 1, 1,1408, 816,1408, 816 }, /* 0x0d: 1280x800 */ + { 1, 1,1900,1066,1900,1066 }, /* 0x0e: 1680x1050 (LVDS) */ + { 1, 1,1408, 806,1408, 806 }, /* 0x0f: 1280x768_2 */ + { 1, 1,1664, 798,1664, 798 }, /* 0x10: 1280x768_3 */ + { 1, 1,1688, 802,1688, 802 }, /* 0x11: 1280x768: Std, TMDS only */ + { 1, 1,1344, 806,1344, 806 } /* 0x12: 1280x720 (LVDS) */ }; -static const SiS_LVDSDataStruct SiS_LCDA1280x1024Data_2[]= -{ /* Corrected (illegal in Acer, correct in Compaq) */ - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066}, - {1688,1066,1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LCDA1400x1050Data_1[]= -{ /* Clevo */ - { 928, 416, 1688,1066}, - { 928, 366, 1688,1066}, - {1008, 416, 1688,1066}, - {1008, 366, 1688,1066}, - {1200, 530, 1688,1066}, - {1088, 616, 1688,1066}, - {1312, 784, 1688,1066}, - {1568,1040, 1688,1066}, - {1688,1066, 1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LCDA1400x1050Data_2[]= -{ /* Clevo */ - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066}, - {1688,1066, 1688,1066} -}; - -static const SiS_LVDSDataStruct SiS_LCDA1600x1200Data_1[]= -{ /* Clevo (Temporary data) */ - {1200, 450, 2048,1250}, - {1200, 400, 2048,1250}, - {1280, 450, 2048,1250}, - {1280, 400, 2048,1250}, - {1200, 530, 2048,1250}, - {1360, 650, 2048,1250}, - {1584, 818, 2048,1250}, - {1688,1066, 2048,1250}, - {1688,1066, 2048,1250}, - {2048,1250, 2048,1250} /* this should be correct */ -#if 0 - {2160,1250, 2048,1250} /* ? */ -#endif -}; - -static const SiS_LVDSDataStruct SiS_LCDA1600x1200Data_2[]= -{ /* Clevo (Temporary data. Seems invalid.) */ - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250}, - {2160,1250, 2160,1250} -}; - -/* LVDS SKEW for LCDA */ - -static const SiS_LVDSDesStruct SiS_PanelType1076_1[]= -{ /* 1024x768 */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, /* 805; was 0, 0 -> top line cut away (26/09/03) */ -}; - -static const SiS_LVDSDesStruct SiS_PanelType1076_2[]= -{ /* 1024x768; not expanded */ - { 1184, 622 }, - { 1184, 597 }, - { 1184, 622 }, - { 1184, 597 }, - { 1152, 650 }, /* 622 */ - { 1232, 722 }, - { 0, 0 }, /* 805; was 0, 0 -> top line cut away (26/09/03) */ -}; - -static const SiS_LVDSDesStruct SiS_PanelType1210_1[]= -{ /* 1280x1024 */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 1065}, /* Acer */ - { 0 , 0} -}; - -static const SiS_LVDSDesStruct SiS_PanelType1210_2[]= -{ /* 1280x1024; not expanded */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - -static const SiS_LVDSDesStruct SiS_PanelType1296_1[]= -{ /* 1400x1050 */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 1065} /* Was 0,0 */ -}; - -static const SiS_LVDSDesStruct SiS_PanelType1296_2[]= -{ /* 1400x1050; not expanded */ - { 1308, 741 }, - { 1308, 716 }, - { 1308, 741 }, - { 1308, 716 }, - { 1308, 781 }, - { 1388, 841 }, - { 1500, 925 }, - { 1628,1053 }, - { 0,1065 } -#if 0 - { 808 , 740}, - { 0 , 715}, - { 632 , 740}, - { 632 , 715}, - { 1307, 780}, - { 1387,1157}, - { 1499, 924}, - { 1627,1052}, - { 0 , 0} -#endif -}; - -static const SiS_LVDSDesStruct SiS_PanelType1600_1[]= -{ /* 1600x1200 */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - -static const SiS_LVDSDesStruct SiS_PanelType1600_2[]= -{ /* 1600x1200; not expanded */ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - -#ifdef SIS315H - -/* LCDA CRT1 custom data */ - -static const SiS_LCDACRT1DataStruct Compaq1280x1024_LCDACRT1_1[]= -{ - {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f, - 0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06, - 0x00}}, - {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x08,0x3e, - 0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06, - 0x00}}, - {{0x92,0x63,0x63,0x96,0x6c,0x1a,0x80,0xf0, - 0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06, - 0x01}}, - {{0xae,0x7f,0x7f,0x92,0x88,0x96,0x28,0xf5, - 0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x9f,0x92,0xa8,0x16,0x28,0x5a, - 0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07, - 0x01}} -}; - -static const SiS_LCDACRT1DataStruct Compaq1280x1024_LCDACRT1_1_H[]= -{ - {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1, - 0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06, - 0x01}}, - {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f, - 0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1, - 0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06, - 0x01}}, - {{0x56,0x27,0x27,0x9a,0x30,0x1e,0x08,0x3e, - 0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05, - 0x00}}, - {{0x60,0x31,0x31,0x84,0x3a,0x88,0x80,0xf0, - 0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01, - 0x01}}, - {{0x6e,0x3f,0x3f,0x92,0x48,0x96,0x28,0xf5, - 0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LCDACRT1DataStruct Clevo1024x768_LCDACRT1_1[]= -{ - {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f, - 0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f, - 0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05, - 0x00}}, - {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x04,0x3e, - 0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05, - 0x00}}, - {{0x87,0x63,0x63,0x8B,0x69,0x1A,0x7c,0xf0, - 0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x26, - 0x01}}, - {{0xA3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LCDACRT1DataStruct Clevo1024x768_LCDACRT1_1_H[]= -{ - {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f, - 0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f, - 0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f, - 0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44, - 0x00}}, - {{0x4b,0x27,0x27,0x8f,0x32,0x1b,0x04,0x3e, - 0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x45, - 0x00}}, - {{0x55,0x31,0x31,0x99,0x46,0x1d,0x7c,0xf0, - 0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55, - 0x01}}, - {{0x63,0x3F,0x3F,0x87,0x4A,0x93,0x24,0xF5, - 0x02,0x88,0xFF,0xFF,0x25,0x10,0x00,0x01, - 0x01}} -}; - -static const SiS_LCDACRT1DataStruct Clevo1024x768_LCDACRT1_2[]= -{ - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb, - 0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06, - 0x00}}, - {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1, - 0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02, - 0x01}}, - {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02, - 0x01}} -}; - -static const SiS_LCDACRT1DataStruct Clevo1024x768_LCDACRT1_2_H[]= -{ - {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x57,0x8e,0x8f,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x3e,0x85,0x5d,0x5d,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x57,0x8e,0x8f,0x8f,0x25,0x30,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x3e,0x85,0x5d,0x5d,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb, - 0x7f,0x86,0xdf,0xdf,0x25,0x10,0x00,0x01, - 0x00 }}, - {{0x71,0x31,0x31,0x95,0x46,0x97,0x24,0xf1, - 0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x01, - 0x01 }}, - {{0x63,0x3f,0x3f,0x87,0x46,0x97,0x24,0xf5, - 0x0f,0x86,0xff,0xff,0x25,0x30,0x00,0x01, - 0x01 }} -}; - -#endif /* 315 */ /**************************************************************/ /* LVDS ----------------------------------------------------- */ @@ -1507,9 +1188,7 @@ { 848, 389,1060, 629}, { 848, 518,1060, 629}, {1056, 628,1056, 628}, - {1056, 628,1056, 628}, - { 800, 449,1000, 644}, - { 800, 525,1000, 635} + {1056, 628,1056, 628} }; static const SiS_LVDSDataStruct SiS_LVDS800x600Data_2[]= @@ -1520,9 +1199,7 @@ {1056, 628,1056, 628}, {1056, 628,1056, 628}, {1056, 628,1056, 628}, - {1056, 628,1056, 628}, - { 800, 449,1000, 644}, - { 800, 525,1000, 635} + {1056, 628,1056, 628} }; static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_1[]= @@ -1534,8 +1211,6 @@ { 840, 518,1344, 806}, /* 640x480 */ {1050, 638,1344, 806}, /* 800x600 */ {1344, 806,1344, 806}, /* 1024x768 */ - { 800, 449,1280, 801}, - { 800, 525,1280, 813} }; static const SiS_LVDSDataStruct SiS_LVDS1024x768Data_2[]= @@ -1547,11 +1222,8 @@ {1344, 806,1344, 806}, {1344, 806,1344, 806}, {1344, 806,1344, 806}, - { 800, 449,1280, 801}, - { 800, 525,1280, 813} }; - static const SiS_LVDSDataStruct SiS_LVDS1280x1024Data_1[]= { {1048, 442,1688,1066}, @@ -1702,9 +1374,7 @@ { 840, 560,1344, 800}, { 840, 689,1344, 800}, {1050, 800,1344, 800}, - {1344, 800,1344, 800}, - { 800, 449,1280, 789}, - { 800, 525,1280, 785} + {1344, 800,1344, 800} }; static const SiS_LVDSDataStruct SiS_LVDS1024x600Data_2[] = @@ -1715,9 +1385,7 @@ {1344, 800,1344, 800}, {1344, 800,1344, 800}, {1344, 800,1344, 800}, - {1344, 800,1344, 800}, - { 800, 449,1280, 801}, - { 800, 525,1280, 813} + {1344, 800,1344, 800} }; static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_1[] = @@ -1728,9 +1396,7 @@ { 840, 409,1344, 806}, { 840, 518,1344, 806}, {1050, 638,1344, 806}, - {1344, 806,1344, 806}, - { 800, 449,1280, 801}, - { 800, 525,1280, 813} + {1344, 806,1344, 806} }; static const SiS_LVDSDataStruct SiS_LVDS1152x768Data_2[] = @@ -1741,9 +1407,7 @@ {1344, 806,1344, 806}, {1344, 806,1344, 806}, {1344, 806,1344, 806}, - {1344, 806,1344, 806}, - { 800, 449,1280, 801}, - { 800, 525,1280, 813} + {1344, 806,1344, 806} }; /* Pass 1:1 data */ @@ -1756,7 +1420,7 @@ { 800, 525, 800, 525}, /* 640x480 */ {1056, 628, 1056, 628}, /* 800x600 */ {1344, 806, 1344, 806}, /* 1024x768 */ - {1344,1066, 1344,1066}, /* 1280x1024 */ /* INSERTED ! */ + {1688,1066, 1688,1066}, /* 1280x1024 */ /* INSERTED ! */ {1688, 806, 1688, 806}, /* 1280x768 */ /* No other panels ! */ }; @@ -1871,36 +1535,6 @@ {1160, 840,1160, 840} }; -/* LVDS Skew */ - -static const SiS_LVDSDesStruct SiS_PanelTypeNS_1[]= -{ - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 8, 0}, - { 0, 0}, - { 0, 0}, - { 0, 0}, - { 0, 806}, - { 0, 0} -}; - -static const SiS_LVDSDesStruct SiS_PanelTypeNS_2[] = -{ - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0}, - { 0 , 0} -}; - /* Chrontel TV Skew */ static const SiS_LVDSDesStruct SiS_CHTVUNTSCDesData[]= @@ -2439,63 +2073,6 @@ 0x01}} }; -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1XXXxXXX_1[] = -{ - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05, - 0x00}}, - {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05, - 0x00}}, - {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x06, - 0x01}}, - {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x02, - 0x01}}, - {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a, - 0x00,0x84,0xff,0x29,0x09,0x00,0x07, - 0x01}}, - {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x07, - 0x01}} -}; - -static const SiS_LVDSCRT1DataStruct SiS_LVDSCRT1XXXxXXX_1_H[] = -{ - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f, - 0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00, - 0x00}}, - {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e, - 0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00, - 0x00}}, - {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0, - 0x58,0x8c,0x57,0x73,0x20,0x00,0x01, - 0x01}}, - {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5, - 0x02,0x88,0xff,0x25,0x10,0x00,0x01, - 0x01}} -}; - - /**************************************************************/ /* COMMON --------------------------------------------------- */ /**************************************************************/ @@ -2756,7 +2333,8 @@ { 0x0000 } }; -USHORT SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN); +USHORT SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, + int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight); USHORT SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN, USHORT CustomT, int LCDwith, int LCDheight); USHORT SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth); @@ -2777,6 +2355,7 @@ void SiS_DisplayOff(SiS_Private *SiS_Pr); void SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr); void SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); +BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); void SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); @@ -2787,6 +2366,7 @@ USHORT SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo); void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex); +void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex); #ifdef LINUX_XF86 BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch); BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn, diff -urN linux-2.4.25/drivers/video/sis/init301.c linux-2.4.26/drivers/video/sis/init301.c --- linux-2.4.25/drivers/video/sis/init301.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/init301.c 2004-04-14 06:05:40.000000000 -0700 @@ -34,13 +34,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -76,10 +73,6 @@ #include "init301.h" -#if 0 -#define TWNEWPANEL -#endif - #ifdef SIS300 #include "oem300.h" #endif @@ -91,6 +84,8 @@ #define SiS_I2CDELAY 1000 #define SiS_I2CDELAYSHORT 150 +static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr); + /*********************************************/ /* HELPER: Lock/Unlock CRT2 */ /*********************************************/ @@ -98,146 +93,75 @@ void SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - if(HwInfo->jChipType >= SIS_315H) - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); - else - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01); + else + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01); } void SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - if(HwInfo->jChipType >= SIS_315H) - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); - else - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); + if(HwInfo->jChipType >= SIS_315H) + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE); + else + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE); } /*********************************************/ -/* HELPER: Enable CRT2 */ +/* HELPER: Write SR11 */ /*********************************************/ -void -SiS_EnableCRT2(SiS_Private *SiS_Pr) +static void +SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR) { - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); + if(HwInfo->jChipType >= SIS_661) DataAND &= 0x0f; + SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR); } /*********************************************/ /* HELPER: Get Pointer to LCD structure */ /*********************************************/ -/* For 661 series only */ #ifdef SIS315H -#if 0 /* Need to wait until hardware using this really exists */ static UCHAR * -GetLCDPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int tabletype, - USHORT ModeNo, USHORT ModeIdIndex, USHORT RRTI) +GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - UCHAR *tableptr = NULL; - UCHAR tablelengths[] = { 8, 7, 6, 6, 8, 6, 0, 0, 0 }; - USHORT modeflag, CRT2Index, tablelength, lcdid, myid, tableptri; - - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - CRT2Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT2CRTC; - /* This is total bullshit: */ - if(SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO == SIS_RI_720x576) CRT2Index = 10; - } - - if(tabletype <= 1) { -#if 0 /* Not yet implemented */ - if(ModeNo <= 0x13) { - CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex]. + 5; - } else { - CRT2Index = SiS_Pr->SiS_RefIndex[RRTI]. + 5; - } - if(tabletype & 1) CRT2Index >>= 4; -#endif - } - - CRT2Index &= 0x0f; - - tablelength = tablelengths[tabletype]; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - if((tabletype == 5) || (tabletype == 7)) tablelength = 8; - if((tabletype == 3) || (tabletype == 8)) tablelength = 8; - } - - if(!tablelength) return NULL; - - tableptri = ROMAddr[0x222] | (ROMAddr[0x223] << 8); - tableptri += (tabletype << 1); - if(!tableptri) return NULL; - tableptr = &ROMAddr[tableptri]; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + UCHAR *myptr = NULL; + USHORT romindex = 0; - do { - lcdid = tableptr[0]; - if(lcdid == 0xff) break; - myid = SiS_Pr->SiS_LCDResInfo; - if((lcdid & 0x80) && (lcdid != 0x80)) { - lcdid &= 0x7f; - myid = SiS_Pr->SiS_LCDTypeInfo; - } - if(SiS_Pr->SiS_LCDInfo & LCDPass11) myid &= ~0x1f; - - if(myid == lcdid) { - lcdid = tableptr[1] | (tableptr[2] << 8); - myid = SiS_Pr->SiS_LCDInfo661; - if(modeflag & HalfDCLK) myid |= 0x200; - if(ModeNo <= 0x13) myid |= 0x400; - lcdid &= myid; - myid = tableptr[3] | (tableptr[4] << 8); - if(lcdid == myid) break; - } - tableptr += 7; - } while (1); - - if(lcdid == myid) { - lcdid = tableptr[5] | (tableptr[6] << 8); - lcdid += (tablelength * CRT2Index); - return((UCHAR *)&ROMAddr[lcdid]); - } + /* Use the BIOS tables only for LVDS panels; DVI is unreliable + * due to the variaty of panels the BIOS doesn't know about. + */ - return NULL; + if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + myptr = (UCHAR *)SiS_LCDStruct661; + romindex = SISGETROMW(0x100); /* 10c, 0.93: 10e */ + if(romindex) { + romindex += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x7d) & 0x1f) * 26); + myptr = &ROMAddr[romindex]; + } + } + return myptr; } -#endif -static UCHAR * -GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +static USHORT +GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT lcdres = SiS_Pr->SiS_LCDResInfo; - USHORT lcdtype = SiS_Pr->SiS_LCDTypeInfo; - USHORT romindex=0; - UCHAR *myptr = NULL; - UCHAR lcdid; + USHORT romptr = 0; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - romindex = ROMAddr[0x256] | (ROMAddr[0x257] << 8); - } - if(romindex) { - myptr = &ROMAddr[romindex]; - } else { - myptr = (UCHAR *)SiS_LCDStruct661; - } + /* Use the BIOS tables only for LVDS panels; DVI is unreliable + * due to the variaty of panels the BIOS doesn't know about. + */ - while(myptr[0] != 0xff) { - lcdid = myptr[0]; - if((lcdid & 0x80) && (lcdid != 0x80)) { - lcdres = lcdtype; - lcdid &= 0x7f; - } - if(lcdid == lcdres) break; - myptr += 26; + if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { + romptr = SISGETROMW(0x102); /* 2ad */ + romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize); } - if(myptr[0] == 0xff) return NULL; - return myptr; + return(romptr); } #endif @@ -250,71 +174,72 @@ USHORT RefreshRateTableIndex, USHORT *i, PSIS_HW_INFO HwInfo) { - USHORT tempax,tempbx,infoflag; - - tempbx = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID; + USHORT checkmask=0,modeid,infoflag; - tempax = 0; + modeid = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID; if(SiS_Pr->SiS_VBType & VB_SISVB) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { - tempax |= SupportRAMDAC2; + checkmask |= SupportRAMDAC2; if(HwInfo->jChipType >= SIS_315H) { - tempax |= SupportRAMDAC2_135; + checkmask |= SupportRAMDAC2_135; if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - tempax |= SupportRAMDAC2_162; + checkmask |= SupportRAMDAC2_162; if(SiS_Pr->SiS_VBType & VB_SIS301C) { - tempax |= SupportRAMDAC2_202; + checkmask |= SupportRAMDAC2_202; } } } } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - tempax |= SupportLCD; + checkmask |= SupportLCD; if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(tempbx == 0x2e) { /* 640x480 */ - tempax |= Support64048060Hz; - } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(modeid == 0x2e) checkmask |= Support64048060Hz; } } } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - tempax |= SupportHiVision; + checkmask |= SupportHiVision; } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) { - tempax |= SupportTV; + checkmask |= SupportTV; if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - tempax |= SupportTV1024; + checkmask |= SupportTV1024; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + checkmask |= SupportYPbPr750p; + } + } } } - } else { /* for LVDS */ + } else { /* LVDS */ if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tempax |= SupportCHTV; + checkmask |= SupportCHTV; } } if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - tempax |= SupportLCD; + checkmask |= SupportLCD; } } /* Look backwards in table for matching CRT2 mode */ - for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == tempbx; (*i)--) { + for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == modeid; (*i)--) { infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; - if(infoflag & tempax) return(1); + if(infoflag & checkmask) return TRUE; if((*i) == 0) break; } @@ -322,17 +247,17 @@ * for a matching CRT2 mode if no mode was found yet. */ for((*i) = 0; ; (*i)++) { - if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) { - return(0); + if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != modeid) { + return FALSE; } infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag; - if(infoflag & tempax) return(1); + if(infoflag & checkmask) return TRUE; } - return(1); + return TRUE; } /*********************************************/ -/* Get rate pointer */ +/* Get rate index */ /*********************************************/ USHORT @@ -357,13 +282,11 @@ if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(modeflag & HalfDCLK) return(0); + if(modeflag & HalfDCLK) return 0; } } - if(ModeNo < 0x14) return(0xFFFF); - - /* CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4]. */ + if(ModeNo < 0x14) return 0xFFFF; index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F; backupindex = index; @@ -378,7 +301,7 @@ } if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) { - temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo]; + temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)]; if(index > temp) index = temp; } } @@ -451,37 +374,39 @@ /* HELPER: GET SOME DATA FROM BIOS ROM */ /*********************************************/ +#ifdef SIS300 static BOOLEAN SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { + UCHAR *ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase; USHORT temp,temp1; - UCHAR *ROMAddr; - if((ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xff) >> 4); - temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b]; - if(temp1 & temp) return(1); + temp1 = SISGETROMW(0x23b); + if(temp1 & temp) return TRUE; } } - return(0); + return FALSE; } static BOOLEAN SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { + UCHAR *ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase; USHORT temp,temp1; - UCHAR *ROMAddr; - if((ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xff) >> 4); - temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d]; - if(temp1 & temp) return(1); + temp1 = SISGETROMW(0x23d); + if(temp1 & temp) return TRUE; } } - return(0); + return FALSE; } +#endif /*********************************************/ /* HELPER: DELAY FUNCTIONS */ @@ -555,7 +480,7 @@ } else { Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; } - if((ROMAddr) && (SiS_Pr->SiS_UseROM)) { + if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x40) { if(!(DelayTime & 0x01)) { Delay = (USHORT)ROMAddr[0x225]; @@ -573,7 +498,15 @@ #ifdef SIS315H - if(HwInfo->jChipType >= SIS_330) return; + if(HwInfo->jChipType >= SIS_661) { + + if(!(DelayTime & 0x01)) { + SiS_DDC2Delay(SiS_Pr, 0x1000); + } else { + SiS_DDC2Delay(SiS_Pr, 0x4000); + } + + } else if(HwInfo->jChipType >= SIS_330) return; if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || @@ -598,7 +531,7 @@ } else { Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1]; } - if((ROMAddr) && (SiS_Pr->SiS_UseROM)) { + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { if(ROMAddr[0x13c] & 0x40) { if(!(DelayTime & 0x01)) { Delay = (USHORT)ROMAddr[0x17e]; @@ -619,10 +552,7 @@ } else { Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1]; } - Delay <<= 2; - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - Delay <<= 5; - } + Delay <<= 8; SiS_DDC2Delay(SiS_Pr, Delay); } @@ -737,10 +667,7 @@ static BOOLEAN SiS_Is301B(SiS_Private *SiS_Pr) { - USHORT flag; - - flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01); - if(flag >= 0xb0) return TRUE; + if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE; return FALSE; } @@ -804,6 +731,27 @@ #ifdef SIS315H static BOOLEAN +SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE; + } + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN +SiS_LCDAEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE; + return FALSE; +} +#endif + +#ifdef SIS315H +static BOOLEAN SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { USHORT flag; @@ -956,7 +904,7 @@ if(!(SiS_Pr->SiS_ChSW)) return; #ifndef LINUX_XF86 - SiS_SetRegLong(0xcf8,0x80000874); /* get ACPI base */ + SiS_SetRegLong(0xcf8,0x80000874); /* get ACPI base */ acpibase = SiS_GetRegLong(0xcfc); #else acpibase = pciReadLong(0x00000800, 0x74); @@ -974,22 +922,19 @@ } void -SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, - USHORT ModeIdIndex,PSIS_HW_INFO HwInfo, - int checkcrt2mode) +SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + PSIS_HW_INFO HwInfo, int checkcrt2mode) { USHORT tempax,tempbx,temp; USHORT modeflag, resinfo=0; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } SiS_Pr->SiS_SetFlag = 0; @@ -1001,11 +946,12 @@ temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); #if 0 if(HwInfo->jChipType < SIS_661) { - if(SiS_Pr->SiS_YPbPr & YPbPrModeMask) { + /* NO - YPbPr not set yet ! */ + if(SiS_Pr->SiS_YPbPr & ) { temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ temp |= SetCRT2ToHiVision; /* 0x80 */ } - if(SiS_Pr->SiS_YPbPr & YPbPrSetSVideo) { + if(SiS_Pr->SiS_YPbPr & ) { temp &= (SetCRT2ToHiVision | SwitchCRT2 | SetSimuScanMode); /* 0x83 */ temp |= SetCRT2ToSVIDEO; /* 0x08 */ } @@ -1040,16 +986,28 @@ if((temp & (EnableDualEdge | SetToLCDA)) == (EnableDualEdge | SetToLCDA)) { tempbx |= SetCRT2ToLCDA; } - if(HwInfo->jChipType >= SIS_661) { - if(SiS_Pr->SiS_VBType & (VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { - if(temp & 0x04) { - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; - if(temp == 0x60) tempbx |= SetCRT2ToHiVision; - else tempbx |= SetCRT2ToYPbPr525750; - } - } - } - } + } + + if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { + tempbx &= ~(SetCRT2ToRAMDAC); + } + + if(HwInfo->jChipType >= SIS_661) { + tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(SiS_Pr->SiS_VBType & (VB_SIS301C|VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + else tempbx |= SetCRT2ToYPbPr525750; + } + } else if(SiS_Pr->SiS_VBType & (VB_SIS301 | VB_SIS301B | VB_SIS302B)) { + if(temp & 0x04) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35) & 0xe0; + if(temp == 0x60) tempbx |= SetCRT2ToHiVision; + } + } + } if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); @@ -1111,24 +1069,12 @@ SetPALTV | SwitchCRT2 | SetSimuScanMode ); - if(tempbx & SetCRT2ToLCDA) { - tempbx &= (clearmask | SetCRT2ToLCDA); - } - if(tempbx & SetCRT2ToRAMDAC) { - tempbx &= (clearmask | SetCRT2ToRAMDAC); - } - if(tempbx & SetCRT2ToLCD) { - tempbx &= (clearmask | SetCRT2ToLCD); - } - if(tempbx & SetCRT2ToSCART) { - tempbx &= (clearmask | SetCRT2ToSCART); - } - if(tempbx & SetCRT2ToHiVision) { - tempbx &= (clearmask | SetCRT2ToHiVision); - } - if(tempbx & SetCRT2ToYPbPr525750) { - tempbx &= (clearmask | SetCRT2ToYPbPr525750); - } + if(tempbx & SetCRT2ToLCDA) tempbx &= (clearmask | SetCRT2ToLCDA); + if(tempbx & SetCRT2ToRAMDAC) tempbx &= (clearmask | SetCRT2ToRAMDAC); + if(tempbx & SetCRT2ToLCD) tempbx &= (clearmask | SetCRT2ToLCD); + if(tempbx & SetCRT2ToSCART) tempbx &= (clearmask | SetCRT2ToSCART); + if(tempbx & SetCRT2ToHiVision) tempbx &= (clearmask | SetCRT2ToHiVision); + if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750); } else { if(HwInfo->jChipType >= SIS_315H) { if(tempbx & SetCRT2ToLCDA) { @@ -1156,14 +1102,12 @@ } } - if(!(tempbx & DriverMode)){ - tempbx |= SetSimuScanMode; - } + if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode; /* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */ if(SiS_Pr->SiS_ModeType <= ModeVGA) { if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || - ((tempbx & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD)) ) { + ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) { modeflag &= (~CRT2Mode); } } @@ -1237,21 +1181,40 @@ void SiS_SetYPbPr(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { + + UCHAR temp; + /* Note: This variable is only used on 30xLV systems. * CR38 has a different meaning on LVDS/CH7019 systems. * On 661 and later, these bits moved to CR35. + * + * On 301, 301B, only HiVision 1080i is supported. + * On 30xLV, 301C, only YPbPr 1080i is supported. */ SiS_Pr->SiS_YPbPr = 0; -#ifdef SIS315H - if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - SiS_Pr->SiS_YPbPr = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & 0x38) >> 3); + if(HwInfo->jChipType >= SIS_661) return; + + if(SiS_Pr->SiS_VBType) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + SiS_Pr->SiS_YPbPr = YPbPrHiVision; + } + } + + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_SIS301C)) { + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38); + if(temp & 0x08) { + switch((temp >> 4)) { + case 0x00: SiS_Pr->SiS_YPbPr = YPbPr525i; break; + case 0x01: SiS_Pr->SiS_YPbPr = YPbPr525p; break; + case 0x02: SiS_Pr->SiS_YPbPr = YPbPr750p; break; + case 0x03: SiS_Pr->SiS_YPbPr = YPbPrHiVision; break; + } } } } -#endif /* SIS315H */ + } /*********************************************/ @@ -1290,7 +1253,7 @@ if(HwInfo->jChipType >= SIS_330) romindex = 0x11b; } if(temp) { - if(romindex && ROMAddr && SiS_Pr->SiS_UseROM) { + if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { OutputSelect = ROMAddr[romindex]; if(!(OutputSelect & EnablePALMN)) { SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F); @@ -1312,8 +1275,8 @@ } /* Translate HiVision/YPbPr to our new flags */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_YPbPr == YPbPr750) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; - else if(SiS_Pr->SiS_YPbPr == YPbPr525) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; + if(SiS_Pr->SiS_YPbPr == YPbPr750p) SiS_Pr->SiS_TVMode |= TVSetYPbPr750p; + else if(SiS_Pr->SiS_YPbPr == YPbPr525p) SiS_Pr->SiS_TVMode |= TVSetYPbPr525p; else if(SiS_Pr->SiS_YPbPr == YPbPrHiVision) SiS_Pr->SiS_TVMode |= TVSetHiVision; else SiS_Pr->SiS_TVMode |= TVSetYPbPr525i; if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetYPbPr525p | TVSetYPbPr525i)) { @@ -1387,6 +1350,22 @@ } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL); } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { + if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39); + if(temp1 & 0x02) { + if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) { + SiS_Pr->SiS_TVMode |= TVAspect169; + } else { + SiS_Pr->SiS_TVMode |= TVAspect43LB; + } + } else { + SiS_Pr->SiS_TVMode |= TVAspect43; + } + } + } } } @@ -1396,6 +1375,7 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { SiS_Pr->SiS_TVMode |= TVSetPAL; + SiS_Pr->SiS_TVMode &= ~(TVSetPALM | TVSetPALN | TVSetNTSCJ); } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525i | TVSetYPbPr525p | TVSetYPbPr750p)) { SiS_Pr->SiS_TVMode &= ~(TVSetPAL | TVSetNTSCJ | TVSetPALM | TVSetPALN); @@ -1409,6 +1389,7 @@ } if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { + /* BIOS sets TVNTSC1024 without checking 525p here. Wrong? */ if(!(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr525p | TVSetYPbPr750p))) { if(resinfo == SIS_RI_1024x768) { SiS_Pr->SiS_TVMode |= TVSetNTSC1024; @@ -1433,15 +1414,48 @@ SiS_Pr->SiS_VBInfo &= ~SetPALTV; #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, "(init301.c: TVMode %x)\n", SiS_Pr->SiS_TVMode); + xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo); #endif - } /*********************************************/ /* GET LCD INFO */ /*********************************************/ +static USHORT +SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr) +{ + USHORT temp = SiS_Pr->SiS_LCDResInfo; + /* Translate my LCDResInfo to BIOS value */ + if(temp == Panel_1280x768_2) temp = Panel_1280x768; + if(temp == Panel_1280x768_3) temp = Panel_1280x768; + return temp; +} + +static void +SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) +{ +#ifdef SIS315H + UCHAR *ROMAddr; + + if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + SiS_Pr->PanelHT = SISGETROMW(6); + SiS_Pr->PanelVT = SISGETROMW(8); + SiS_Pr->PanelHRS = SISGETROMW(10); + SiS_Pr->PanelHRE = SISGETROMW(12); + SiS_Pr->PanelVRS = SISGETROMW(14); + SiS_Pr->PanelVRE = SISGETROMW(16); + SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (USHORT)ROMAddr[18]; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19]; + SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B = + SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20]; + } +#endif +} + void SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo) @@ -1457,49 +1471,57 @@ { 0, 1, 2, 3, 7, 4, 5, 8, 0, 0, 10, 0, 0, 0, 0, 15 }; - SiS_Pr->SiS_LCDResInfo = 0; + SiS_Pr->SiS_LCDResInfo = 0; SiS_Pr->SiS_LCDTypeInfo = 0; - SiS_Pr->SiS_LCDInfo = 0; + SiS_Pr->SiS_LCDInfo = 0; + SiS_Pr->PanelHRS = 999; /* HSync start */ + SiS_Pr->PanelHRE = 999; /* HSync end */ + SiS_Pr->PanelVRS = 999; /* VSync start */ + SiS_Pr->PanelVRE = 999; /* VSync end */ - if(SiS_Pr->UseCustomMode) { + if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return; + + if(ModeNo <= 0x13) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { modeflag = SiS_Pr->CModeFlag; } else { - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } - if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return; - temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36); - if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) { + if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) { + SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2; + } else if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) { SiS_Pr->SiS_LCDTypeInfo = temp >> 4; } else { SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1; } temp &= 0x0f; if(HwInfo->jChipType < SIS_315H) { - /* Translate 300 series LCDRes to 315 series for unified usage */ - temp = SiS300SeriesLCDRes[temp]; + /* Translate 300 series LCDRes to 315 series for unified usage */ + temp = SiS300SeriesLCDRes[temp]; } - SiS_Pr->SiS_LCDResInfo = temp; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301) - SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301; - } else { - if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS) - SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS; + if(HwInfo->jChipType == SIS_550) { + if(temp == Panel310_640x480_2) temp = Panel_640x480_2; + if(temp == Panel310_640x480_3) temp = Panel_640x480_3; } - if((!SiS_Pr->CP_HaveCustomData) || (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_PanelCustom)) { - if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax) - SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768; - } + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { /* SiS LVDS */ + if(temp == Panel310_1280x768) { + temp = Panel_1280x768_2; +#ifdef SIS315H + if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if((myptr[8] | (myptr[9] << 8)) == 798) temp = Panel_1280x768_3; + } +#endif + } + } + + SiS_Pr->SiS_LCDResInfo = temp; if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { @@ -1509,113 +1531,285 @@ } } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301; + } else { + if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS) + SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS; + } + + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + switch(SiS_Pr->SiS_LCDResInfo) { - case Panel_800x600: SiS_Pr->PanelXRes = 800; SiS_Pr->PanelYRes = 600; break; - case Panel_1024x768: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; break; - case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; break; - case Panel_640x480_3: + case Panel_320x480: SiS_Pr->PanelXRes = 320; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 400; SiS_Pr->PanelVT = 525; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; case Panel_640x480_2: - case Panel_640x480: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; break; - case Panel_1024x600: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 600; break; - case Panel_1152x864: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 864; break; - case Panel_1280x960: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 960; break; - case Panel_1152x768: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 768; break; - case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; break; - case Panel_1280x768: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; break; - case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; break; - case Panel_320x480: SiS_Pr->PanelXRes = 320; SiS_Pr->PanelYRes = 480; break; - case Panel_Custom: SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX; - SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; - break; - case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; break; - case Panel_848x480: SiS_Pr->PanelXRes = 848; SiS_Pr->PanelYRes = 480; break; - default: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; break; + case Panel_640x480_3: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRS = 24; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_640x480: SiS_Pr->PanelXRes = 640; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK28; + SiS_Pr->PanelVCLKIdx315 = VCLK28; + break; + case Panel_800x600: SiS_Pr->PanelXRes = 800; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1056; SiS_Pr->PanelVT = 628; + SiS_Pr->PanelHRS = 40; SiS_Pr->PanelHRE = 128; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 4; + SiS_Pr->PanelVCLKIdx300 = VCLK40; + SiS_Pr->PanelVCLKIdx315 = VCLK40; + break; + case Panel_1024x600: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 600; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 800; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 2 /* 88 */ ; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1024x768: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; SiS_Pr->PanelHRE = 136; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(HwInfo->jChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1152x768: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 24; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + if(HwInfo->jChipType < SIS_315H) { + SiS_Pr->PanelHRS = 23; + SiS_Pr->PanelVRE = 5; + } + SiS_Pr->PanelVCLKIdx300 = VCLK65_300; + SiS_Pr->PanelVCLKIdx315 = VCLK65_315; + break; + case Panel_1152x864: SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes = 864; + break; + case Panel_1280x720: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 720; + SiS_Pr->PanelHT = 1650; SiS_Pr->PanelVT = 750; + SiS_Pr->PanelHRS = 110; SiS_Pr->PanelHRE = 40; + SiS_Pr->PanelVRS = 5; SiS_Pr->PanelVRE = 5; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720; + /* Data above for TMDS (projector); get from BIOS for LVDS */ + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x768: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 802; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRS = 112; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx300 = VCLK81_300; + SiS_Pr->PanelVCLKIdx315 = VCLK81_315; + break; + case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 806; + SiS_Pr->PanelHRS = 16; SiS_Pr->PanelHRE = 64; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x768_3: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1664; SiS_Pr->PanelVT = 798; + SiS_Pr->PanelHRS = 64; SiS_Pr->PanelHRE = 128; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 7; + SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_3; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x800: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 800; + SiS_Pr->PanelHT = 1408; SiS_Pr->PanelVT = 816; + SiS_Pr->PanelHRS = 21; SiS_Pr->PanelHRE = 24; + SiS_Pr->PanelVRS = 4; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK69_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1280x960: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 960; + SiS_Pr->PanelHT = 1800; SiS_Pr->PanelVT = 1000; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315; + if(resinfo == SIS_RI_1280x1024) { + SiS_Pr->PanelVCLKIdx300 = VCLK100_300; + SiS_Pr->PanelVCLKIdx315 = VCLK100_315; + } + break; + case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 112; /* HRE OK for LVDS, not for LCDA */ + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; + SiS_Pr->PanelHT = 2160; SiS_Pr->PanelVT = 1250; + SiS_Pr->PanelHRS = 64; SiS_Pr->PanelHRE = 192; + SiS_Pr->PanelVRS = 1; SiS_Pr->PanelVRE = 3; + SiS_Pr->PanelVCLKIdx315 = VCLK162_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_1680x1050: SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050; + SiS_Pr->PanelHT = 1900; SiS_Pr->PanelVT = 1066; + SiS_Pr->PanelHRS = 26; SiS_Pr->PanelHRE = 76; + SiS_Pr->PanelVRS = 3; SiS_Pr->PanelVRE = 6; + SiS_Pr->PanelVCLKIdx315 = VCLK121_315; + SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo); + break; + case Panel_Custom: SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX; + SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY; + SiS_Pr->PanelHT = SiS_Pr->CHTotal; + SiS_Pr->PanelVT = SiS_Pr->CVTotal; + if(SiS_Pr->CP_PreferredIndex != -1) { + SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHT = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVT = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRE = SiS_Pr->CP_HSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRS = SiS_Pr->CP_VSyncStart[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelVRE = SiS_Pr->CP_VSyncEnd[SiS_Pr->CP_PreferredIndex]; + SiS_Pr->PanelHRS -= SiS_Pr->PanelXRes; + SiS_Pr->PanelHRE -= SiS_Pr->PanelHRS; + SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes; + SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS; + } + break; + case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; + SiS_Pr->PanelHT = 1688; SiS_Pr->PanelVT = 1066; + break; + case Panel_848x480: SiS_Pr->PanelXRes = 848; SiS_Pr->PanelYRes = 480; + SiS_Pr->PanelHT = 1088; SiS_Pr->PanelVT = 525; + break; + default: SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes = 768; + SiS_Pr->PanelHT = 1344; SiS_Pr->PanelVT = 806; + break; } temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); - if(HwInfo->jChipType < SIS_661) { - temp &= ~0xe; - } else { + SiS_Pr->SiS_LCDInfo = temp & ~0x000e; + + if(!(SiS_Pr->UsePanelScaler)) SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + #ifdef SIS315H - if(!(temp & 0x10)) { - if(temp & 0x08) temp |= LCDPass11; + if(HwInfo->jChipType >= SIS_661) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11; } - temp &= ~0xe; if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - myptr = GetLCDStructPtr661(SiS_Pr, HwInfo); - if(myptr) { - if(myptr[2] & 0x01) temp |= LCDDualLink; - } + if(SiS_Pr->SiS_ROMNew) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } else if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) { + if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } else if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11; } + if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) { + SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit); + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35); + if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit; + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } + } #endif + + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + /* Always center screen on LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + /* Always center screen on SiS LVDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } else { + /* By default, pass 1:1 on SiS TMDS (if scaling is disabled) */ + SiS_Pr->SiS_LCDInfo |= LCDPass11; + if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11; + } } - SiS_Pr->SiS_LCDInfo = temp; if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { - SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24 */ + SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20; /* neg h/v sync, RGB24(D0 = 0) */ } } - if(!(SiS_Pr->UsePanelScaler)) SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; - else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - if(SiS_Pr->SiS_VBType & VB_SISVB) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) { - /* For non-standard LCD resolution, we let the panel scale */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e) { - /* We do not scale to 1280x960 (B/C bridges only) */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - if(((HwInfo->jChipType >= SIS_315H) && (ModeNo == 0x23 || ModeNo == 0x24 || ModeNo == 0x25)) || - ((HwInfo->jChipType < SIS_315H) && (ModeNo == 0x55 || ModeNo == 0x5a || ModeNo == 0x5b))) { - /* We do not scale to 1280x768 (B/C bridges only) */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - /* No non-scaling data available for LV bridges */ - SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - /* No idea about the timing and zoom factors */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) { - /* We do not scale to 1280x1024 (all bridges) */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { - /* No idea about the timing and zoom factors (C bridge only) */ - SiS_Pr->SiS_LCDInfo |= DontExpandLCD; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; - } - } + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_Custom: + /* For non-standard LCD resolution, we let the panel scale */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + case Panel_1280x720: + if(SiS_Pr->PanelHT == 1650) { + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + case Panel_1280x768: /* TMDS only */ + /* No idea about the timing and zoom factors */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + break; + case Panel_1280x960: + SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD; + break; + case Panel_1280x1024: + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e || + ModeNo == 0x79 || ModeNo == 0x75 || ModeNo == 0x78 || + ModeNo == 0x14 || ModeNo == 0x15 || ModeNo == 0x16) { + /* We do not scale to 1280x720/800/960 (B/C bridges only) */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + if(((HwInfo->jChipType >= SIS_315H) && + (ModeNo == 0x23 || ModeNo == 0x24 || ModeNo == 0x25)) || + ((HwInfo->jChipType < SIS_315H) && + (ModeNo == 0x55 || ModeNo == 0x5a || ModeNo == 0x5b))) { + /* We do not scale to 1280x768 (B/C bridges only) */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + } + break; + case Panel_1400x1050: + if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) { + /* We do not scale to 1280x1024 (all bridges) */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; + case Panel_1600x1200: + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + /* No idea about the timing and zoom factors (C bridge only) */ + SiS_Pr->SiS_LCDInfo |= DontExpandLCD; + } + break; } } } - if(HwInfo->jChipType >= SIS_315H) { -#ifdef SIS315H - if(HwInfo->jChipType < SIS_661) { - if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) { - SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); - SiS_Pr->SiS_LCDInfo |= LCDPass11; - } - } -#endif - } else { #ifdef SIS300 + if(HwInfo->jChipType < SIS_315H) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { if(!(ROMAddr[0x235] & 0x02)) { SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); @@ -1627,34 +1821,59 @@ SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); } } + } #endif + + /* Special cases */ + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11); + } + + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) { + SiS_Pr->SiS_LCDInfo |= LCDPass11; + } + + /* (In)validate LCDPass11 flag */ + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + SiS_Pr->SiS_LCDInfo &= ~LCDPass11; } - /* Trumpion: Assume non-expanding */ - if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0) { - SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD); + /* Special cases */ + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + SiS_Pr->PanelHRS = 999; + SiS_Pr->PanelHRE = 999; } - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - SiS_Pr->SiS_LCDInfo &= (~LCDPass11); + if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || + (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + SiS_Pr->PanelVRS = 999; + SiS_Pr->PanelVRE = 999; } #ifdef SIS315H if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { - if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - /* Enable 302LV/302ELV dual link mode. - * For 661, this is done above. - */ - if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)) { - /* (Sets this in SenseLCD; new paneltypes) */ - SiS_Pr->SiS_LCDInfo |= LCDDualLink; - } - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) { - SiS_Pr->SiS_LCDInfo |= LCDDualLink; - } + if(!(SiS_Pr->SiS_ROMNew)) { + if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { + /* Enable 302LV/302ELV dual link mode. + * For 661, this is done above. + */ + if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) { + /* (Sets this in SenseLCD; new paneltypes) */ + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) { + SiS_Pr->SiS_LCDInfo |= LCDDualLink; + } + } } } #endif @@ -1662,37 +1881,37 @@ if(!((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) { if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) { - if(ModeNo > 0x13) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { - SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { + if(ModeNo == 0x12) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } } - } - } - } - if(ModeNo == 0x12) { - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } } } } if(modeflag & HalfDCLK) { - if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if(!(((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (HwInfo->jChipType < SIS_315H)) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480))) { - if(ModeNo > 0x13) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) { - if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } - } - } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; - } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) { + SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(ModeNo > 0x13) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) { + if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA; + } + } } } @@ -1705,14 +1924,6 @@ SiS_Pr->SiS_SetFlag |= LCDVESATiming; } - SiS_Pr->SiS_LCDInfo661 = 0; - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) SiS_Pr->SiS_LCDInfo661 |= 0x0001; - if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) SiS_Pr->SiS_LCDInfo661 |= 0x0002; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) SiS_Pr->SiS_LCDInfo661 |= 0x0008; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) SiS_Pr->SiS_LCDInfo661 |= 0x0010; - SiS_Pr->SiS_LCDInfo661 |= (SiS_Pr->SiS_LCDInfo & 0xe0); - if(SiS_Pr->SiS_LCDInfo & LCDDualLink) SiS_Pr->SiS_LCDInfo661 |= 0x0100; - #ifdef LINUX_KERNEL #ifdef TWDEBUG printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n", @@ -1734,54 +1945,21 @@ SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) { - USHORT tempbx; - const USHORT LCDXlat0VCLK[4] = {VCLK40, VCLK40, VCLK40, VCLK40}; - const USHORT LVDSXlat1VCLK[4] = {VCLK40, VCLK40, VCLK40, VCLK40}; - const USHORT LVDSXlat4VCLK[4] = {VCLK28, VCLK28, VCLK28, VCLK28}; -#ifdef SIS300 - const USHORT LCDXlat1VCLK300[4] = {VCLK65_300, VCLK65_300, VCLK65_300, VCLK65_300}; - const USHORT LCDXlat2VCLK300[4] = {VCLK108_2_300,VCLK108_2_300,VCLK108_2_300,VCLK108_2_300}; - const USHORT LVDSXlat2VCLK300[4]= {VCLK65_300, VCLK65_300, VCLK65_300, VCLK65_300}; - const USHORT LVDSXlat3VCLK300[4]= {VCLK65_300, VCLK65_300, VCLK65_300, VCLK65_300}; -#endif -#ifdef SIS315H - const USHORT LCDXlat1VCLK310[4] = {VCLK65_315, VCLK65_315, VCLK65_315, VCLK65_315}; - const USHORT LCDXlat2VCLK310[4] = {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315}; - const USHORT LVDSXlat2VCLK310[4]= {VCLK65_315, VCLK65_315, VCLK65_315, VCLK65_315}; - const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315}; -#endif - USHORT CRT2Index,VCLKIndex=0; - USHORT modeflag,resinfo; - const UCHAR *CHTVVCLKPtr = NULL; - const USHORT *LCDXlatVCLK1 = NULL; - const USHORT *LCDXlatVCLK2 = NULL; - const USHORT *LVDSXlatVCLK2 = NULL; - const USHORT *LVDSXlatVCLK3 = NULL; - - if(HwInfo->jChipType >= SIS_315H) { -#ifdef SIS315H - LCDXlatVCLK1 = LCDXlat1VCLK310; - LCDXlatVCLK2 = LCDXlat2VCLK310; - LVDSXlatVCLK2 = LVDSXlat2VCLK310; - LVDSXlatVCLK3 = LVDSXlat3VCLK310; -#endif - } else { -#ifdef SIS300 - LCDXlatVCLK1 = LCDXlat1VCLK300; - LCDXlatVCLK2 = LCDXlat2VCLK300; - LVDSXlatVCLK2 = LVDSXlat2VCLK300; - LVDSXlatVCLK3 = LVDSXlat3VCLK300; -#endif - } + USHORT CRT2Index,VCLKIndex=0,VCLKIndexGEN=0; + USHORT modeflag,resinfo,tempbx; + const UCHAR *CHTVVCLKPtr = NULL; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03; } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; + if(HwInfo->jChipType < SIS_315H) VCLKIndexGEN &= 0x3f; } if(SiS_Pr->SiS_VBType & VB_SISVB) { /* 30x/B/LV */ @@ -1789,50 +1967,18 @@ if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { CRT2Index >>= 6; - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { /* LCD */ if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) { - VCLKIndex = LCDXlat0VCLK[CRT2Index]; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - VCLKIndex = LCDXlatVCLK1[CRT2Index]; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) { - VCLKIndex = LCDXlatVCLK1[CRT2Index]; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) { - VCLKIndex = LCDXlatVCLK1[CRT2Index]; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - VCLKIndex = VCLK81_300; /* guessed */ - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) { - VCLKIndex = VCLK108_3_300; - if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_300; - } else { - VCLKIndex = LCDXlatVCLK2[CRT2Index]; - } + VCLKIndex = SiS_Pr->PanelVCLKIdx300; } else { - if( (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) || - (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - VCLKIndex = VCLK108_2_315; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - VCLKIndex = VCLK81_315; /* guessed */ - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - VCLKIndex = VCLK108_2_315; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - VCLKIndex = VCLK162_315; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) { - VCLKIndex = VCLK108_3_315; - if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_315; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - VCLKIndex = LCDXlatVCLK1[CRT2Index]; - } else { - VCLKIndex = LCDXlatVCLK2[CRT2Index]; - } - } else { - VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02)); /* Port 3cch */ - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if(ModeNo > 0x13) { - VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - } + VCLKIndex = SiS_Pr->PanelVCLKIdx315; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) { + VCLKIndex = VCLKIndexGEN; + if(resinfo == SIS_RI_1280x720) VCLKIndex = VCLK_1280x720; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x720) { + if(SiS_Pr->PanelHT == 1344) VCLKIndex = VCLK_1280x720_2; + } if(ModeNo <= 0x13) { if(HwInfo->jChipType <= SIS_315PRO) { if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42; @@ -1848,34 +1994,28 @@ } } - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* TV */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; - else VCLKIndex = HiTVVCLK; + if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2; + else VCLKIndex = HiTVVCLK; if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(modeflag & Charx8Dot) VCLKIndex = HiTVSimuVCLK; - else VCLKIndex = HiTVTextVCLK; + if(modeflag & Charx8Dot) VCLKIndex = HiTVSimuVCLK; + else VCLKIndex = HiTVTextVCLK; } - } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK - TVCLKBASE_315; - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; - else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; - else VCLKIndex = TVVCLK; + } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) VCLKIndex = TVVCLKDIV2; + else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = TVVCLKDIV2; + else VCLKIndex = TVVCLK; - if(HwInfo->jChipType < SIS_315H) { - VCLKIndex += TVCLKBASE_300; - } else { - VCLKIndex += TVCLKBASE_315; - } + if(HwInfo->jChipType < SIS_315H) VCLKIndex += TVCLKBASE_300; + else VCLKIndex += TVCLKBASE_315; - } else { /* VGA2 */ + } else { /* VGA2 */ - VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if(ModeNo > 0x13) { - VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) { - VCLKIndex &= 0x3f; + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { if( (HwInfo->jChipType == SIS_630) && (HwInfo->jChipRevision >= 0x30)) { if(VCLKIndex == 0x14) VCLKIndex = 0x34; @@ -1888,12 +2028,9 @@ } else { /* If not programming CRT2 */ - VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if(ModeNo > 0x13) { - VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) { - VCLKIndex &= 0x3f; + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { if( (HwInfo->jChipType != SIS_630) && (HwInfo->jChipType != SIS_300) ) { if(VCLKIndex == 0x1b) VCLKIndex = 0x35; @@ -1906,7 +2043,7 @@ VCLKIndex = CRT2Index; - if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { /* programming CRT2 */ + if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) { if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) { @@ -1942,32 +2079,16 @@ } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - VCLKIndex >>= 6; - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480)) - VCLKIndex = LVDSXlat1VCLK[VCLKIndex]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) - VCLKIndex = LVDSXlat4VCLK[VCLKIndex]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) - VCLKIndex = LVDSXlatVCLK2[VCLKIndex]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) - VCLKIndex = LVDSXlatVCLK2[VCLKIndex]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) - VCLKIndex = LVDSXlatVCLK2[VCLKIndex]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) - VCLKIndex = VCLK68_315; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) - VCLKIndex = VCLK162_315; - else - VCLKIndex = LVDSXlatVCLK3[VCLKIndex]; - - if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - /* Special Timing: Barco iQ Pro R series */ - VCLKIndex = 0x44; + if(HwInfo->jChipType < SIS_315H) { + VCLKIndex = SiS_Pr->PanelVCLKIdx300; + } else { + VCLKIndex = SiS_Pr->PanelVCLKIdx315; } + /* Special Timing: Barco iQ Pro R series */ + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44; + + /* Special Timing: 848x480 parallel lvds */ if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { if(HwInfo->jChipType < SIS_315H) { VCLKIndex = VCLK34_300; @@ -1980,28 +2101,22 @@ } else { - VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if(ModeNo > 0x13) { - VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) { - VCLKIndex &= 0x3F; + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { + if( (HwInfo->jChipType == SIS_630) && + (HwInfo->jChipRevision >= 0x30) ) { + if(VCLKIndex == 0x14) VCLKIndex = 0x2e; + } } - if( (HwInfo->jChipType == SIS_630) && - (HwInfo->jChipRevision >= 0x30) ) { - if(VCLKIndex == 0x14) VCLKIndex = 0x2e; - } } } } else { /* if not programming CRT2 */ - VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02)); - VCLKIndex = ((VCLKIndex >> 2) & 0x03); - if(ModeNo > 0x13) { - VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK; - if(HwInfo->jChipType < SIS_315H) { - VCLKIndex &= 0x3F; + VCLKIndex = VCLKIndexGEN; + if(HwInfo->jChipType < SIS_315H) { + if(ModeNo > 0x13) { if( (HwInfo->jChipType != SIS_630) && (HwInfo->jChipType != SIS_300) ) { if(VCLKIndex == 0x1b) VCLKIndex = 0x35; @@ -2045,12 +2160,10 @@ if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } /* BIOS does not do this (neither 301 nor LVDS) */ @@ -2168,8 +2281,8 @@ } if((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301)) { - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x960)) { tempah |= 0x80; } } else { @@ -2196,9 +2309,9 @@ } } - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) || - ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) && + if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x960) || + ((SiS_Pr->SiS_LCDResInfo == Panel_Custom) && (SiS_Pr->CP_MaxX >= 1280) && (SiS_Pr->CP_MaxY >= 960))) { tempah |= 0x80; } @@ -2336,7 +2449,7 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah); } - /* 661: Sets p4 27 and 34 here, done in SetGroup4 here */ + /* 661: Sets p4 27 and 34 here, done in SetGroup4 here (old BIOS) */ #endif /* SIS315H */ @@ -2398,14 +2511,8 @@ USHORT SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex) { - USHORT resindex; - - if(ModeNo <= 0x13) - resindex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; - else - resindex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - - return(resindex); + if(ModeNo <= 0x13) return((USHORT)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo); + else return((USHORT)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO); } static void @@ -2415,8 +2522,12 @@ USHORT xres,yres,modeflag=0,resindex; if(SiS_Pr->UseCustomMode) { - SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = SiS_Pr->CHDisplay; - SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = SiS_Pr->CVDisplay; + xres = SiS_Pr->CHDisplay; + if(SiS_Pr->CModeFlag & HalfDCLK) xres *= 2; + SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; + yres = SiS_Pr->CVDisplay; + if(SiS_Pr->CModeFlag & DoubleScanMode) yres *= 2; + SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; return; } @@ -2431,7 +2542,7 @@ modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } - if((!SiS_Pr->SiS_IF_DEF_DSTN) && (!SiS_Pr->SiS_IF_DEF_FSTN)) { + if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) { if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) { if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) { @@ -2442,72 +2553,64 @@ } } - if(ModeNo > 0x13) { - if(modeflag & HalfDCLK) xres *= 2; - if(modeflag & DoubleScanMode) yres *= 2; - } + if(modeflag & HalfDCLK) xres *= 2; + if(modeflag & DoubleScanMode) yres *= 2; } - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToHiVision)) { if(xres == 720) xres = 640; - } else { - if(SiS_Pr->SiS_VBType & VB_NoLCD) { /* 301BDH */ - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { - if(xres == 720) xres = 640; - } - if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - yres = 400; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; - } else { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; - } - } - } else { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { - if(xres == 720) xres = 640; - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(yres == 1024) yres = 1056; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - /* BIOS bug - does this regardless of scaling */ - if(yres == 400) yres = 405; - } - if(yres == 350) yres = 360; - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { - if(yres == 360) yres = 375; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if(yres == 350) yres = 357; - if(yres == 400) yres = 420; - if(yres == 480) yres = 525; - } - } - } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_1024x768: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + if(yres == 350) yres = 357; + if(yres == 400) yres = 420; + if(yres == 480) yres = 525; + } + } + break; + case Panel_1280x1024: + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + /* BIOS bug - does this regardless of scaling */ + if(yres == 400) yres = 405; } + if(yres == 350) yres = 360; + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + if(yres == 360) yres = 375; + } + break; + case Panel_1600x1200: + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(yres == 1024) yres = 1056; + } + break; } } + } else { - if(xres == 720) xres = 640; - if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - yres = 400; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; - } else { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; - } - if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) { - yres = 480; - } + + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) { + if(xres == 720) xres = 640; } + } else if(xres == 720) xres = 640; + + if(SiS_Pr->SiS_SetFlag & SetDOSMode) { + yres = 400; + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480; + } else { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480; + } + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) yres = 480; + } + } SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres; SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres; @@ -2522,103 +2625,84 @@ USHORT RefreshRateTableIndex, USHORT *ResIndex, USHORT *DisplayType) { - USHORT tempbx,modeflag=0; - USHORT Flag,CRT2CRTC; + USHORT modeflag=0; if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; } } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE; } else return FALSE; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; } - Flag = 1; - tempbx = 0; - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - Flag = 0; - tempbx = 18; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - tempbx += 2; - if(SiS_Pr->SiS_ModeType > ModeVGA) { - if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; - } - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - tempbx = 18; /* PALM uses NTSC data */ - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++; - } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { - tempbx = 20; /* PALN uses PAL data */ - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++; - } - } + (*ResIndex) &= 0x3F; + + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + (*DisplayType) = 18; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + (*DisplayType) += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 99; + } + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + (*DisplayType) = 18; /* PALM uses NTSC data */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + (*DisplayType) = 20; /* PALN uses PAL data */ + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++; + } + } + } else { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: (*DisplayType) = 50; break; + case Panel_640x480_2: (*DisplayType) = 52; break; + case Panel_640x480_3: (*DisplayType) = 54; break; + case Panel_800x600: (*DisplayType) = 0; break; + case Panel_1024x600: (*DisplayType) = 23; break; + case Panel_1024x768: (*DisplayType) = 4; break; + case Panel_1152x768: (*DisplayType) = 27; break; + case Panel_1280x768: (*DisplayType) = 40; break; + case Panel_1280x1024: (*DisplayType) = 8; break; + case Panel_1400x1050: (*DisplayType) = 14; break; + case Panel_1600x1200: (*DisplayType) = 36; break; + default: return FALSE; } - } - if(Flag) { - tempbx = SiS_Pr->SiS_LCDResInfo; - tempbx -= SiS_Pr->SiS_PanelMinLVDS; - if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 6; - if(modeflag & HalfDCLK) tempbx += 3; - } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - tempbx = 14; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) { - tempbx = 23; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) { - tempbx = 27; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tempbx = 36; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - tempbx = 40; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) { - tempbx = 54; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) { - tempbx = 52; - if(modeflag & HalfDCLK) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) { - tempbx = 50; - if(modeflag & HalfDCLK) tempbx++; - } + if(modeflag & HalfDCLK) (*DisplayType)++; + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + case Panel_640x480_2: + case Panel_640x480_3: + break; + default: + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2; } + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - tempbx = 12; - if(modeflag & HalfDCLK) tempbx++; + (*DisplayType) = 12; + if(modeflag & HalfDCLK) (*DisplayType)++; } } #if 0 if(SiS_Pr->SiS_IF_DEF_FSTN) { if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){ - tempbx = 22; + (*DisplayType) = 22; } } #endif - *ResIndex = CRT2CRTC & 0x3F; - *DisplayType = tempbx; return TRUE; } @@ -2627,8 +2711,7 @@ USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex, PSIS_HW_INFO HwInfo) { - USHORT tempbx=0,tempal=0; - USHORT Flag,resinfo=0; + USHORT tempbx=0,tempal=0,resinfo=0; if(ModeNo <= 0x13) { tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; @@ -2641,55 +2724,30 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { /* LCD */ - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) { - tempbx = 15; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - tempbx = 20; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 21; - else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 22; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tempbx = 23; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 24; - else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 25; -#if 0 - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - tempbx = 26; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 27; - else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 28; -#endif - } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx = 13; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 14; - else { - tempbx = 29; - if(ModeNo >= 0x13) { - /* see below */ - if(resinfo == SIS_RI_1280x960) tempal = 10; - } - } - } else { - tempbx = 29; - if(ModeNo >= 0x13) { - /* 1280x768 and 1280x960 have same CRT2CRTC, - * so we change it here if 1280x960 is chosen - */ - if(resinfo == SIS_RI_1280x960) tempal = 10; + tempbx = SiS_Pr->SiS_LCDResInfo; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32; + + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { /* Pass 1:1 only (center-screen handled outside) */ + tempbx = 100; + if(ModeNo >= 0x13) { + tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) && + (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 768)) { + /* Special for Fujitsu 7911 (VL-17WDX8), others custom */ + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768) tempal = 0x08; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_2) tempal = 0x0f; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_3) tempal = 0x10; } - } - } else { - tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_Panel1024x768; - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - tempbx += 10; - } + } } #ifdef SIS315H if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tempbx = 50; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 51; - else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 52; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + tempbx = 200; + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++; + } } } #endif @@ -2697,10 +2755,11 @@ } else { /* TV */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); + /* if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_TVMode &= (~TVSetTVSimuMode); */ tempbx = 2; if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 13; + tempbx = 13; + if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) tempbx = 14; } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) tempbx = 7; @@ -2727,9 +2786,14 @@ } if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { - if(resinfo == SIS_RI_1024x768) { + if(resinfo == SIS_RI_1024x768) tempal = 8; + } + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + if((resinfo == SIS_RI_720x576) || + (resinfo == SIS_RI_768x576)) { tempal = 8; } + if(resinfo == SIS_RI_1280x720) tempal = 9; } } } @@ -2740,70 +2804,54 @@ } else { /* LVDS, 301B-DH (if running on LCD) */ - Flag = 1; tempbx = 0; - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - Flag = 0; - tempbx = 10; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - tempbx += 2; - if(SiS_Pr->SiS_ModeType > ModeVGA) { - if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; - } - if(SiS_Pr->SiS_TVMode & TVSetPALM) { - tempbx = 90; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { - tempbx = 92; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; - } - } - } - } - - if(Flag) { - - if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) { - tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3; - - if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { - tempbx = 82; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + tempbx = 10; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tempbx += 2; + if(SiS_Pr->SiS_ModeType > ModeVGA) { + if(SiS_Pr->SiS_CHSOverScan) tempbx = 99; } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) { - tempbx = 18; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) { - tempbx = 6; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) { - tempbx = 30; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) { - tempbx = 30; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) { - tempbx = 15; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) { - tempbx = 16; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - tempbx = 8; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tempbx = 21; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelBarco1366) { - tempbx = 80; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + if(SiS_Pr->SiS_TVMode & TVSetPALM) { + tempbx = 90; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } else if(SiS_Pr->SiS_TVMode & TVSetPALN) { + tempbx = 92; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + } + } + } else { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: tempbx = 6; break; + case Panel_640x480_2: tempbx = 30; break; + case Panel_640x480_3: tempbx = 30; break; + case Panel_800x600: tempbx = 0; break; + case Panel_1024x600: tempbx = 15; break; + case Panel_1024x768: tempbx = 2; break; + case Panel_1152x768: tempbx = 17; break; + case Panel_1280x768: tempbx = 18; break; + case Panel_1280x1024: tempbx = 4; break; + case Panel_1400x1050: tempbx = 8; break; + case Panel_1600x1200: tempbx = 21; break; + case Panel_Barco1366: tempbx = 80; break; + } + + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + case Panel_640x480_2: + case Panel_640x480_3: + break; + default: + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; } - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - tempbx = 7; - } + if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 7; - if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { + if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { + tempbx = 82; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; + } else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) { tempbx = 84; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; } @@ -2811,45 +2859,17 @@ } if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempal = 7; + if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) tempal = 7; if(HwInfo->jChipType < SIS_315H) { if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++; } } - *CRT2Index = tempbx; - *ResIndex = tempal & 0x1F; + (*CRT2Index) = tempbx; + (*ResIndex) = tempal & 0x1F; } } -#ifdef SIS315H -static void -SiS_GetCRT2PtrA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex,USHORT *CRT2Index, - USHORT *ResIndex) -{ - USHORT tempbx,tempal; - - tempbx = SiS_Pr->SiS_LCDResInfo; - - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 4; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 3; - else tempbx -= SiS_Pr->SiS_Panel1024x768; - - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 5; - - if(ModeNo <= 0x13) - tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - else - tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - - /* No customs required yet (Clevo, Compaq, etc) */ - - *CRT2Index = tempbx; - *ResIndex = tempal & 0x1F; -} -#endif - static void SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo) @@ -2910,8 +2930,7 @@ static void SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) + USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) { USHORT CRT2Index, ResIndex; const SiS_LVDSDataStruct *LVDSData = NULL; @@ -2929,23 +2948,55 @@ SiS_Pr->SiS_RY4COE = 0; } - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { #ifdef SIS315H - SiS_GetCRT2PtrA(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, - &CRT2Index,&ResIndex); - - switch (CRT2Index) { - case 0: LVDSData = SiS_Pr->SiS_LCDA1024x768Data_1; break; - case 1: LVDSData = SiS_Pr->SiS_LCDA1280x1024Data_1; break; - case 3: LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_1; break; - case 4: LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_1; break; - case 5: LVDSData = SiS_Pr->SiS_LCDA1024x768Data_2; break; - case 6: LVDSData = SiS_Pr->SiS_LCDA1280x1024Data_2; break; - case 8: LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_2; break; - case 9: LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_2; break; - default: LVDSData = SiS_Pr->SiS_LCDA1024x768Data_1; break; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->UseCustomMode) { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->CHTotal; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal; + } else { + if(ModeNo < 0x13) { + ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else { + ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS; + /* Special for our 3 types, others custom (works with default) */ + if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) && + (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 768)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768) ResIndex = 0x08; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_2) ResIndex = 0x0f; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_3) ResIndex = 0x10; + } + /* Special for 1280x720 TMDS <> LVDS */ + if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) && + (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes == 720)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x720) { + if(SiS_Pr->PanelHT == 1344) ResIndex = 0x12; + } + } + } + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT; + SiS_Pr->SiS_HT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT; + SiS_Pr->SiS_VT = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT; + } + } else { + SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + } + } else { + /* This handles custom modes and custom panels */ + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE); + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE); } + + SiS_CalcLCDACRT1Timing(SiS_Pr,ModeNo,ModeIdIndex); + #endif } else { @@ -2956,7 +3007,7 @@ } SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &CRT2Index, &ResIndex, HwInfo); + &CRT2Index, &ResIndex, HwInfo); /* 301BDH needs LVDS Data */ if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { @@ -2964,72 +3015,59 @@ } switch (CRT2Index) { - case 0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; - case 1: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; - case 2: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1; break; - case 3: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2; break; - case 4: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2; break; - case 5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2; break; - case 6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; - case 7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1; break; - case 8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1; break; - case 9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2; break; - case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; - case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; - case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; - case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; - case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1; break; - case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; - case 16: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1; break; - case 17: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2; break; - case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2; break; - case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1; break; - case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2; break; - case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1; break; - case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2; break; - case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2; break; - case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; - case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; - case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; - case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2; break; - case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1; break; - case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2; break; - case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; - case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; - case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; - case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; - case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; /* Super Overscan */ - default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; - } - } - - SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; - SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; - SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; - SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; - - if(SiS_Pr->SiS_VBType & VB_SISVB) { - - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; - SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; - } + case 0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1; break; + case 1: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2; break; + case 2: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; + case 3: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2; break; + case 4: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1; break; + case 5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2; break; + case 6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1; break; + case 7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1; break; + case 8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1; break; + case 9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2; break; + case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData; break; + case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData; break; + case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData; break; + case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData; break; + case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1; break; + case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1; break; + case 16: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2; break; + case 17: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1; break; + case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2; break; + case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1; break; + case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2; break; + case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1; break; + case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2; break; + case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2; break; + case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1; break; + case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2; break; + case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1; break; + case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2; break; + case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1; break; + case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2; break; + case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData; break; + case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData; break; + case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData; break; + case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData; break; + case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData; break; /* Super Overscan */ + default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1; break; + } + + SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT; - } else { - - if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { + if(!(SiS_Pr->SiS_VBType & VB_SISVB)) { if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) { - SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; - SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; - - if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { - if(ResIndex < 0x08) { - SiS_Pr->SiS_HDE = 1280; - SiS_Pr->SiS_VDE = 1024; - } - } + if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) { + SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes; + SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes; + if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) { + if(ResIndex < 0x08) { + SiS_Pr->SiS_HDE = 1280; + SiS_Pr->SiS_VDE = 1024; + } } } } @@ -3051,14 +3089,12 @@ if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - resinfo = 0; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } SiS_Pr->SiS_NewFlickerMode = 0; @@ -3086,6 +3122,7 @@ } else { SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { @@ -3094,19 +3131,20 @@ &CRT2Index,&ResIndex,HwInfo); switch(CRT2Index) { - case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; - case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; - case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; - case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; - case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; - case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; - case 8: TVPtr = SiS_Pr->SiS_StPALData; break; - case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; - case 10: TVPtr = SiS_Pr->SiS_St525iData; break; - case 11: TVPtr = SiS_Pr->SiS_St525pData; break; - case 12: TVPtr = SiS_Pr->SiS_St750pData; break; - case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; - default: TVPtr = SiS_Pr->SiS_StPALData; break; + case 2: TVPtr = SiS_Pr->SiS_ExtHiTVData; break; + case 3: TVPtr = SiS_Pr->SiS_ExtPALData; break; + case 4: TVPtr = SiS_Pr->SiS_ExtNTSCData; break; + case 5: TVPtr = SiS_Pr->SiS_Ext525iData; break; + case 6: TVPtr = SiS_Pr->SiS_Ext525pData; break; + case 7: TVPtr = SiS_Pr->SiS_Ext750pData; break; + case 8: TVPtr = SiS_Pr->SiS_StPALData; break; + case 9: TVPtr = SiS_Pr->SiS_StNTSCData; break; + case 10: TVPtr = SiS_Pr->SiS_St525iData; break; + case 11: TVPtr = SiS_Pr->SiS_St525pData; break; + case 12: TVPtr = SiS_Pr->SiS_St750pData; break; + case 13: TVPtr = SiS_Pr->SiS_St1HiTVData; break; + case 14: TVPtr = SiS_Pr->SiS_St2HiTVData; break; + default: TVPtr = SiS_Pr->SiS_StPALData; break; } SiS_Pr->SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX; @@ -3123,9 +3161,11 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(resinfo == SIS_RI_1024x768) SiS_Pr->SiS_NewFlickerMode = 0x40; - if(resinfo == SIS_RI_1280x1024) SiS_Pr->SiS_NewFlickerMode = 0x40; - if(resinfo == SIS_RI_1280x720) SiS_Pr->SiS_NewFlickerMode = 0x40; + if((resinfo == SIS_RI_1024x768) || + (resinfo == SIS_RI_1280x1024) || + (resinfo == SIS_RI_1280x720)) { + SiS_Pr->SiS_NewFlickerMode = 0x40; + } if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_TVMode |= TVSetTVSimuMode; @@ -3135,10 +3175,12 @@ if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { SiS_Pr->SiS_HT = StHiTVHT; SiS_Pr->SiS_VT = StHiTVVT; +#if 0 if(!(modeflag & Charx8Dot)) { SiS_Pr->SiS_HT = StHiTextTVHT; SiS_Pr->SiS_VT = StHiTextTVVT; } +#endif } } @@ -3183,10 +3225,11 @@ } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_Pr->SiS_RVBHCMAX = 1; + SiS_Pr->SiS_RVBHCFACT = 1; + if(SiS_Pr->UseCustomMode) { - SiS_Pr->SiS_RVBHCMAX = 1; - SiS_Pr->SiS_RVBHCFACT = 1; SiS_Pr->SiS_VGAHT = SiS_Pr->CHTotal; SiS_Pr->SiS_VGAVT = SiS_Pr->CVTotal; SiS_Pr->SiS_HT = SiS_Pr->CHTotal; @@ -3196,58 +3239,68 @@ } else { - SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, - &CRT2Index,&ResIndex,HwInfo); + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + + SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT; + SiS_Pr->SiS_HT = SiS_Pr->PanelHT; + SiS_Pr->SiS_VT = SiS_Pr->PanelVT; + + } else { + + SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex, + &CRT2Index,&ResIndex,HwInfo); - switch(CRT2Index) { - case 0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; /* VESA Timing */ - case 1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; /* VESA Timing */ - case 5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data; break; /* Obviously unused */ - case 6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data; break; /* Obviously unused */ - case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data; break; /* Non-VESA Timing */ - case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; /* Non-VESA Timing */ - case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768; break; /* Non-expanding */ - case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024; break; /* Non-expanding */ - case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data; break; /* 1280x960 */ - case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; /* VESA Timing */ - case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050; break; /* Non-expanding (let panel scale) */ - case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; /* Non-VESA Timing (let panel scale) */ - case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; /* VESA Timing */ - case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200; break; /* Non-expanding */ - case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; /* Non-VESA Timing */ - case 26: LCDPtr = SiS_Pr->SiS_ExtLCD1280x768Data; break; /* VESA Timing */ - case 27: LCDPtr = SiS_Pr->SiS_NoScaleData1280x768; break; /* Non-expanding */ - case 28: LCDPtr = SiS_Pr->SiS_StLCD1280x768Data; break; /* Non-VESA Timing */ - case 29: LCDPtr = SiS_Pr->SiS_NoScaleData; break; /* Generic no-scale data */ -#ifdef SIS315H - case 50: LCDPtr = (SiS_LCDDataStruct *)SiS310_ExtCompaq1280x1024Data; break; - case 51: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024; break; - case 52: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; -#endif - default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; - } - - SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; - SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; - SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; - SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; - SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; - SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; + switch(CRT2Index) { + case Panel_1024x768 : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + case Panel_1024x768 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data; break; + case Panel_1280x720 : + case Panel_1280x720 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data; break; + case Panel_1280x768_2 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break; + case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data; break; + case Panel_1280x768_3 : + case Panel_1280x768_3+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x768_3Data; break; + case Panel_1280x800 : + case Panel_1280x800 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data; break; + case Panel_1280x960 : + case Panel_1280x960 + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data; break; + case Panel_1280x1024 : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data; break; + case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; + case Panel_1400x1050 : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data; break; + case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data; break; + case Panel_1600x1200 : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data; break; + case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data; break; + case Panel_1680x1050 : + case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data; break; + case 100 : LCDPtr = SiS_Pr->SiS_NoScaleData; break; +#ifdef SIS315H + case 200 : LCDPtr = SiS310_ExtCompaq1280x1024Data; break; + case 201 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data; break; +#endif + default : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data; break; + } #ifdef TWDEBUG - xf86DrvMsg(0, X_INFO, - "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); + xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex); #endif - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - tempax = 1024; + SiS_Pr->SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX; + SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT; + SiS_Pr->SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT; + SiS_Pr->SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT; + SiS_Pr->SiS_HT = (LCDPtr+ResIndex)->LCDHT; + SiS_Pr->SiS_VT = (LCDPtr+ResIndex)->LCDVT; + + } + + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelYRes; + + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { if(HwInfo->jChipType < SIS_315H) { if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; - else tempbx = 768; - } else { - tempbx = 768; } } else { if (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527; @@ -3256,43 +3309,27 @@ else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775; else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560; else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640; - else tempbx = 768; } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tempax = 1280; - if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; - else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; - else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; - else tempbx = 1024; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) { - tempax = 1280; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) { if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 700; else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 800; else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960; - else tempbx = 960; - } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) && - (HwInfo->jChipType >= SIS_661)) { - tempax = 1400; - tempbx = 1050; - if(SiS_Pr->SiS_VGAVDE == 1024) { - tempax = 1280; - tempbx = 1024; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tempax = 1600; - tempbx = 1200; - if((HwInfo->jChipType < SIS_661) || (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))) { + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768; + else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800; + else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864; + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { if (SiS_Pr->SiS_VGAVDE == 350) tempbx = 875; else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 1000; } - } else { - tempax = SiS_Pr->PanelXRes; - tempbx = SiS_Pr->PanelYRes; - } + } + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { tempax = SiS_Pr->SiS_VGAHDE; tempbx = SiS_Pr->SiS_VGAVDE; } + SiS_Pr->SiS_HDE = tempax; SiS_Pr->SiS_VDE = tempbx; } @@ -3306,31 +3343,15 @@ if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - - SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - - } else { - - if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - - /* Need LVDS Data for LCD on 301B-DH */ - SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - - } else { - - SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - - } - - } - + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); } else { - - SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { + /* Need LVDS Data for LCD on 301B-DH */ + SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } else { + SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); + } } } else { @@ -3341,7 +3362,7 @@ } /*********************************************/ -/* GET LVDS DES DATA */ +/* GET LVDS DES (SKEW) DATA */ /*********************************************/ static void @@ -3349,106 +3370,55 @@ USHORT RefreshRateTableIndex, USHORT *PanelIndex, USHORT *ResIndex, PSIS_HW_INFO HwInfo) { - USHORT tempbx,tempal,modeflag; + USHORT modeflag; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; } - tempbx = 0; + (*ResIndex) &= 0x1F; + (*PanelIndex) = 0; + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tempbx = 50; - if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) tempbx += 2; - if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1; + (*PanelIndex) = 50; + if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) (*PanelIndex) += 2; + if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*PanelIndex) += 1; /* Nothing special needed for SOverscan */ - /* PALM uses NTSC data, PALN uses PAL data */ + /* PALM uses NTSC data, PALN uses PAL data */ } } if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - tempbx = SiS_Pr->SiS_LCDTypeInfo; + *PanelIndex = SiS_Pr->SiS_LCDTypeInfo; if(HwInfo->jChipType >= SIS_661) { /* As long as we don's use the BIOS tables, we * need to convert the TypeInfo as for 315 series */ - tempbx = SiS_Pr->SiS_LCDResInfo - 1; + (*PanelIndex) = SiS_Pr->SiS_LCDResInfo - 1; } - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 16; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - tempbx = 32; - if(modeflag & HalfDCLK) tempbx++; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + (*PanelIndex) += 16; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + (*PanelIndex) = 32; + if(modeflag & HalfDCLK) (*PanelIndex)++; + } } } if(SiS_Pr->SiS_SetFlag & SetDOSMode) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - tempal = 0x07; + if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { + (*ResIndex) = 7; if(HwInfo->jChipType < SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++; + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) (*ResIndex)++; } } } - - *PanelIndex = tempbx; - *ResIndex = tempal & 0x1F; -} - -#ifdef SIS315H -static void -SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - USHORT RefreshRateTableIndex, USHORT *PanelIndex, USHORT *ResIndex, - PSIS_HW_INFO HwInfo) -{ - USHORT tempbx=0,tempal; - - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 2; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 3; - else tempbx = SiS_Pr->SiS_LCDResInfo - 2; - - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 4; - - if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - tempbx = 80; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } - } - } - if((SiS_Pr->SiS_CustomT == CUT_UNIWILL1024) || - (SiS_Pr->SiS_CustomT == CUT_UNIWILL10242)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - tempbx = 82; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } - } - if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tempbx = 84; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } - } - if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - tempbx = 86; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++; - } - } - - if(ModeNo <= 0x13) - tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; - else - tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - - *PanelIndex = tempbx; - *ResIndex = tempal & 0x1F; } -#endif static void SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, @@ -3458,39 +3428,43 @@ USHORT PanelIndex,ResIndex; const SiS_LVDSDesStruct *PanelDesPtr = NULL; - if((SiS_Pr->UseCustomMode) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848)) { - SiS_Pr->SiS_LCDHDES = 0; - SiS_Pr->SiS_LCDVDES = 0; + SiS_Pr->SiS_LCDHDES = 0; + SiS_Pr->SiS_LCDVDES = 0; + + if( (SiS_Pr->UseCustomMode) || + (SiS_Pr->SiS_LCDResInfo == Panel_Custom) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) || + ((SiS_Pr->SiS_VBType & VB_SISVB) && + (SiS_Pr->SiS_LCDInfo & DontExpandLCD) && + (SiS_Pr->SiS_LCDInfo & LCDPass11)) ) { return; } if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { #ifdef SIS315H - SiS_GetLVDSDesPtrA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &PanelIndex, &ResIndex, HwInfo); - - switch (PanelIndex) - { - case 0: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1; break; /* --- expanding --- */ - case 1: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_1; break; - case 2: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_1; break; - case 3: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_1; break; - case 4: PanelDesPtr = SiS_Pr->LVDS1024x768Des_2; break; /* --- non expanding --- */ - case 5: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_2; break; - case 6: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_2; break; - case 7: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_2; break; - case 80: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_1; break; /* custom */ - case 81: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_2; break; - case 82: PanelDesPtr = (SiS_LVDSDesStruct *)Uniwill1024x768Des_1; break; - case 83: PanelDesPtr = (SiS_LVDSDesStruct *)Uniwill1024x768Des_2; break; - case 84: PanelDesPtr = (SiS_LVDSDesStruct *)Compaq1280x1024Des_1; break; - case 85: PanelDesPtr = (SiS_LVDSDesStruct *)Compaq1280x1024Des_2; break; - case 86: PanelDesPtr = (SiS_LVDSDesStruct *)Asus1024x768Des_1; break; /* custom */ - case 87: PanelDesPtr = (SiS_LVDSDesStruct *)Asus1024x768Des_2; break; - default: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1; break; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + /* non-pass 1:1 only, see above */ + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) { + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2); + SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2); + } + } + if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) { + switch(SiS_Pr->SiS_CustomT) { + case CUT_UNIWILL1024: + case CUT_UNIWILL10242: + case CUT_CLEVO1400: + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + break; + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) { + SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1; + } + } } #endif @@ -3499,87 +3473,68 @@ SiS_GetLVDSDesPtr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &PanelIndex, &ResIndex, HwInfo); - switch (PanelIndex) - { - case 0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1; break; /* --- */ - case 1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1; break; - case 2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1; break; - case 3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1; break; - case 4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1; break; - case 5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1; break; - case 6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1; break; - case 7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1; break; - case 8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1; break; - case 9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1; break; - case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1; break; - case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1; break; - case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1; break; - case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1; break; - case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1; break; - case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1; break; - case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2; break; /* --- */ - case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2; break; - case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2; break; - case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2; break; - case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2; break; - case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2; break; - case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2; break; - case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2; break; - case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2; break; - case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2; break; - case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2; break; - case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2; break; - case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2; break; - case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2; break; - case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2; break; - case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2; break; - case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1; break; /* pass 1:1 */ - case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2; break; - case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break; /* TV */ - case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break; - case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData; break; - case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData; break; - default: - if(HwInfo->jChipType < SIS_315H) - PanelDesPtr = SiS_Pr->SiS_PanelType0e_1; - else - PanelDesPtr = SiS_Pr->SiS_PanelType01_1; - break; - } - } - SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; - SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; - - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD){ - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - if(!(modeflag & HalfDCLK)) { - SiS_Pr->SiS_LCDHDES = 632; - } - } - } else { - if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) { - if(SiS_Pr->SiS_LCDResInfo >= SiS_Pr->SiS_Panel1024x768) { - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - if(HwInfo->jChipType < SIS_315H) { - if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; - } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) - SiS_Pr->SiS_LCDHDES = 480; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) - SiS_Pr->SiS_LCDHDES = 804; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) - SiS_Pr->SiS_LCDHDES = 704; - if(!(modeflag & HalfDCLK)) { - SiS_Pr->SiS_LCDHDES = 320; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) - SiS_Pr->SiS_LCDHDES = 632; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) - SiS_Pr->SiS_LCDHDES = 542; - } + switch(PanelIndex) { + case 0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1; break; /* --- */ + case 1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1; break; + case 2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1; break; + case 3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1; break; + case 4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1; break; + case 5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1; break; + case 6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1; break; + case 7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1; break; + case 8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1; break; + case 9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1; break; + case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1; break; + case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1; break; + case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1; break; + case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1; break; + case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1; break; + case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1; break; + case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2; break; /* --- */ + case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2; break; + case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2; break; + case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2; break; + case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2; break; + case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2; break; + case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2; break; + case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2; break; + case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2; break; + case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2; break; + case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2; break; + case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2; break; + case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2; break; + case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2; break; + case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2; break; + case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2; break; + case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1; break; /* pass 1:1 */ + case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2; break; + case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break; /* TV */ + case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break; + case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData; break; + case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData; break; + default: return; + } + + SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES; + SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES; + + if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { + modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632; + } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) { + if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) { + if(HwInfo->jChipType < SIS_315H) { + if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) SiS_Pr->SiS_LCDHDES = 480; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704; + if(!(modeflag & HalfDCLK)) { + SiS_Pr->SiS_LCDHDES = 320; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542; } } } @@ -3590,18 +3545,6 @@ } /*********************************************/ -/* SET CRT2 AUTO-THRESHOLD */ -/*********************************************/ - -#ifdef SIS315H -static void -SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr) -{ - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); -} -#endif - -/*********************************************/ /* DISABLE VIDEO BRIDGE */ /*********************************************/ @@ -3617,7 +3560,6 @@ #endif USHORT temp=0; - if(SiS_Pr->SiS_VBType & VB_SISVB) { if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* ===== For 30xB/LV ===== */ @@ -3651,7 +3593,7 @@ } else { if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); SiS_PanelDelay(SiS_Pr, HwInfo, 3); } if(SiS_Is301B(SiS_Pr)) { @@ -3668,7 +3610,7 @@ if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) { SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); } } @@ -3686,7 +3628,7 @@ #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); } } #endif @@ -3916,10 +3858,12 @@ } else { /* ============ For 301 ================ */ if(HwInfo->jChipType < SIS_315H) { +#ifdef SIS300 if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); SiS_PanelDelay(SiS_Pr, HwInfo, 3); } +#endif } SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF); /* disable VB */ @@ -3937,12 +3881,14 @@ SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp); } else { +#ifdef SIS300 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF); /* disable CRT2 */ if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); } +#endif } } @@ -3962,7 +3908,7 @@ SiS_WaitVBRetrace(SiS_Pr,HwInfo); } if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); SiS_PanelDelay(SiS_Pr, HwInfo, 3); } } else { @@ -3973,7 +3919,7 @@ if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) { SiS_DisplayOff(SiS_Pr); } - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); SiS_PanelDelay(SiS_Pr, HwInfo, 3); } } @@ -3992,7 +3938,7 @@ if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) || (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) { SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); } #endif /* SIS300 */ @@ -4032,7 +3978,7 @@ } if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08); SiS_PanelDelay(SiS_Pr, HwInfo, 3); } @@ -4101,14 +4047,14 @@ if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { SiS_PanelDelay(SiS_Pr, HwInfo, 2); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04); } } } #endif /* SIS315H */ - } /* 310 series */ + } /* 315 series */ } /* LVDS */ @@ -4176,7 +4122,7 @@ if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) { /* This is only for LCD output on 301B-DH via LVDS */ - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) { SiS_PanelDelay(SiS_Pr, HwInfo, 0); } @@ -4195,7 +4141,7 @@ SiS_PanelDelay(SiS_Pr, HwInfo, 1); } SiS_WaitVBRetrace(SiS_Pr,HwInfo); - SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x00); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); } } } else { @@ -4229,29 +4175,18 @@ SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef); #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); } #endif } if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { tempah = 0x10; - if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || - (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) { - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) { - if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) { - tempah = 0x08; - } else { - tempah = 0x18; - } - } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); - } else { - if(SiS_IsVAMode(SiS_Pr,HwInfo)) { - tempah = 0x08; - } - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah); + if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { + if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18; + else tempah = 0x08; } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); } if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) && @@ -4300,13 +4235,11 @@ if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) { tempah = 0x10; - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) { - tempah = 0x18; - if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) == 0x0c) { - tempah = 0x08; - } + if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { + if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18; + else tempah = 0x08; } - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah); } } @@ -4316,10 +4249,7 @@ if(SiS_BridgeInSlave(SiS_Pr)) { tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30); if(!(tempah & SetCRT2ToRAMDAC)) { - if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) || - (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) { - if(!(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04)) temp |= 0x20; - } else temp |= 0x20; + if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20; } } SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp); @@ -4385,7 +4315,7 @@ if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) { #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); } #endif SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c); @@ -4630,7 +4560,7 @@ if(HwInfo->jChipType < SIS_315H) { if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); SiS_PanelDelay(SiS_Pr, HwInfo, 0); } } @@ -4663,7 +4593,7 @@ if(HwInfo->jChipType < SIS_315H) { if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); } } @@ -4681,13 +4611,13 @@ SiS_PanelDelay(SiS_Pr, HwInfo, 1); SiS_PanelDelay(SiS_Pr, HwInfo, 1); } - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) { SiS_PanelDelay(SiS_Pr, HwInfo, 0); } } - SiS_EnableCRT2(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_DisplayOn(SiS_Pr); SiS_UnLockCRT2(SiS_Pr,HwInfo); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF); @@ -4712,7 +4642,7 @@ SiS_PanelDelay(SiS_Pr, HwInfo, 1); } SiS_WaitVBRetrace(SiS_Pr, HwInfo); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); } } } @@ -4725,12 +4655,12 @@ if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) { if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00); SiS_PanelDelay(SiS_Pr, HwInfo, 0); } } - SiS_EnableCRT2(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_UnLockCRT2(SiS_Pr,HwInfo); SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7); @@ -4804,7 +4734,7 @@ if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) { if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) { SiS_PanelDelay(SiS_Pr, HwInfo, 1); - SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00); } } } @@ -4821,33 +4751,31 @@ /* SET PART 1 REGISTER GROUP */ /*********************************************/ -/********** Set CRT2 OFFSET / PITCH **********/ +/* Set CRT2 OFFSET / PITCH */ static void -SiS_SetCRT2Offset(SiS_Private *SiS_Pr,USHORT ModeNo, - USHORT ModeIdIndex ,USHORT RefreshRateTableIndex, - PSIS_HW_INFO HwInfo) +SiS_SetCRT2Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, + USHORT RRTI, PSIS_HW_INFO HwInfo) { USHORT offset; UCHAR temp; if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return; - offset = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - HwInfo); + offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI,HwInfo); - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) offset >>= 1; + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { + offset >>= 1; + } - temp = (UCHAR)(offset & 0xFF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,temp); - temp = (UCHAR)(offset >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8)); temp = (UCHAR)(((offset >> 3) & 0xFF) + 1); if(offset % 8) temp++; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp); } -/************* Set CRT2 Sync *************/ +/* Set CRT2 sync and PanelLink mode */ static void SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) @@ -4869,23 +4797,27 @@ } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) { tempah = SiS_Pr->SiS_LCDInfo; } else tempah = infoflag >> 8; - tempah &= 0xC0; - tempah |= 0x20; if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - tempah |= 0xc0; + tempah |= 0xf0; + } + if( (SiS_Pr->SiS_IF_DEF_FSTN) || + (SiS_Pr->SiS_IF_DEF_DSTN) || + (SiS_Pr->SiS_IF_DEF_TRUMPION) || + (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) { + tempah |= 0x30; } } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { if(HwInfo->jChipType >= SIS_315H) { tempah >>= 3; + tempah &= 0x18; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah); + /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */ } else { SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0); } @@ -4902,19 +4834,21 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { /* 630 - 301B(-DH) */ tempah = infoflag >> 8; + tempbl = 0; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { if(SiS_Pr->SiS_LCDInfo & LCDSync) { tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; } } tempah &= 0xC0; - tempah |= 0x20; if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - - tempah &= 0x3f; - tempah |= tempbl; + tempah |= 0xc0; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } } else { /* 630 - 301 */ @@ -4932,43 +4866,72 @@ #ifdef SIS315H /* ------- 315 series ------ */ - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { /* 315 - 30xLV */ + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { /* 315 - LVDS */ - if(((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) || - ((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050))) { + tempbl = 0; + if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { tempah = infoflag >> 8; + if(SiS_Pr->SiS_LCDInfo & LCDSync) { + tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); + } + } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) { + tempah = infoflag >> 8; + tempbl = 0x03; } else { tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); + tempbl = (tempah >> 6) & 0x03; + tempbl |= 0x08; + if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04; } tempah &= 0xC0; - tempah |= 0x20; if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) tempah |= 0xc0; SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } + } - } else { /* 315 - 301, 301B */ + } else { /* 315 - TMDS */ - tempah = infoflag >> 8; + tempah = tempbl = infoflag >> 8; if(!SiS_Pr->UseCustomMode) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + tempbl = 0; + if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + if(ModeNo <= 0x13) { + tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + } + } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(SiS_Pr->SiS_LCDInfo & LCDSync) { tempah = SiS_Pr->SiS_LCDInfo; + tempbl = (tempah >> 6) & 0x03; } } } tempah &= 0xC0; - tempah |= 0x20; if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10; - - if(SiS_Pr->SiS_VBType & VB_NoLCD) { /* TEST, imitate BIOS bug */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - tempah |= 0xc0; + if(SiS_Pr->SiS_VBType & VB_NoLCD) { + /* Imitate BIOS bug */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempah |= 0xc0; + } + if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) { + tempah >>= 3; + tempah &= 0x18; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl); + } } } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah); } #endif /* SIS315H */ @@ -4976,7 +4939,7 @@ } } -/******** Set CRT2 FIFO on 300/630/730 *******/ +/* Set CRT2 FIFO on 300/630/730 */ #ifdef SIS300 static void SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo, @@ -5031,7 +4994,7 @@ if(!SiS_Pr->CRT1UsesCustomMode) { - CRT1ModeNo = SiS_Pr->SiS_CRT1Mode; /* get CRT1 ModeNo */ + CRT1ModeNo = SiS_Pr->SiS_CRT1Mode; /* get CRT1 ModeNo */ SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex); SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); SiS_Pr->SiS_SelectCRT2Rate = 0; @@ -5040,7 +5003,7 @@ if(CRT1ModeNo >= 0x13) { index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK; index &= 0x3F; - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex); /* Get colordepth */ colorth >>= 1; @@ -5050,9 +5013,9 @@ } else { CRT1ModeNo = 0xfe; - VCLK = SiS_Pr->CSRClock_CRT1; /* Get VCLK */ + VCLK = SiS_Pr->CSRClock_CRT1; /* Get VCLK */ data2 = (SiS_Pr->CModeFlag_CRT1 & ModeInfoFlag) - 2; - switch(data2) { /* Get color depth */ + switch(data2) { /* Get color depth */ case 0 : colorth = 1; break; case 1 : colorth = 1; break; case 2 : colorth = 2; break; @@ -5199,10 +5162,10 @@ index = SiS_GetVCLK2Ptr(SiS_Pr,CRT2ModeNo,modeidindex, refreshratetableindex,HwInfo); - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ + VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; /* Get VCLK */ if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x01) { VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8); } @@ -5212,11 +5175,11 @@ } else { CRT2ModeNo = 0xfe; - VCLK = SiS_Pr->CSRClock; /* Get VCLK */ + VCLK = SiS_Pr->CSRClock; /* Get VCLK */ } - colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */ + colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */ colorth >>= 1; if(!colorth) colorth++; @@ -5235,8 +5198,8 @@ if(HwInfo->jChipType == SIS_300) { if(data <= 0x0f) temp = (temp & (~0x1F)) | 0x13; else temp = (temp & (~0x1F)) | 0x16; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - temp = (temp & (~0x1F)) | 0x13; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + temp = (temp & (~0x1F)) | 0x13; } } else { if( ( (HwInfo->jChipType == SIS_630) || @@ -5266,280 +5229,21 @@ } #endif -/**** Set CRT2 FIFO on 315/330 series ****/ -#ifdef SIS315H -static void -SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr) -{ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B); - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,0x04); -} -#endif - -/*************** Set LCD-A ***************/ +/* Set CRT2 FIFO on 315/330 series */ #ifdef SIS315H static void -SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) +SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - USHORT modeflag,resinfo; - USHORT push2,tempax,tempbx,tempcx,temp; - ULONG tempeax=0,tempebx,tempecx,tempvcfact; - - /* This is not supported with LCDA */ - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return; - if(SiS_Pr->UseCustomMode) return; - - if(IS_SIS330) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); /* Xabre 1.01.03 */ - } else if(IS_SIS740) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* 740/LVDS */ - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); /* 740/LVDS */ - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03); - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); /* 740/301LV, 301BDH */ - } - } else { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { /* 650/LVDS */ - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); /* 650/LVDS */ - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00); /* 650/LVDS 1.10.07 */ - } else if(SiS_Pr->SiS_VBType & VB_SISVB) { - SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f); /* 650/30xLv 1.10.6s */ - } - } - - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } - - tempax = SiS_Pr->SiS_LCDHDES; - - temp = (tempax & 0x0007); /* BPLHDESKEW[2:0] */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* Part1_1Ah */ - temp = (tempax >> 3) & 0x00FF; /* BPLHDESKEW[10:3] */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* Part1_16h */ - - tempbx = SiS_Pr->SiS_HDE; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempbx = SiS_Pr->PanelXRes; - } - - tempax += tempbx; /* HDE + HSKEW = lcdhdee */ - if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT; - - temp = tempax; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(temp & 0x07) temp += 8; - } - temp >>= 3; /* BPLHDEE */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* Part1_17h */ - - tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2; /* (HT-HDE) / 4 */ - - /* 650/30xLV 1.10.6s, 740/LVDS */ - if( ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) || - ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 0x28; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempcx = 0x18; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x30; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x40; - else tempcx = 0x30; - } - } - - tempcx += tempax; /* lcdhrs */ - if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT; - - temp = (tempcx >> 3) & 0x00FF; /* BPLHRS */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* Part1_14h */ - - temp += 10; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - temp += 6; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) { - temp++; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) { - temp += 7; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) { - temp -= 10; - } - } - } - } - } - } - temp &= 0x1F; - temp |= ((tempcx & 0x07) << 5); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* Part1_15h */ - - if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { - tempax = SiS_Pr->PanelYRes; - } else { - tempax = SiS_Pr->SiS_VGAVDE; - } - - tempbx = SiS_Pr->SiS_LCDVDES + tempax; - if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; - push2 = tempbx; - - tempcx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 2; - - if( ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) || - ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 1; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempcx = 3; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) tempcx = 3; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 1; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 1; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 1; - else tempcx = 0x0057; - } - } - - tempbx += tempcx; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempbx++; /* BPLVRS */ - } - if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); /* Part1_18h */ - - tempcx >>= 3; - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 3; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempcx = 5; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) tempcx = 5; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 5; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 2; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 2; - } - } - } - tempcx += tempbx; - tempcx++; /* BPLVRE */ - temp = tempcx & 0x000F; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - temp |= 0xC0; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); /* Part1_19h */ - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); - } - - temp = ((tempbx >> 8) & 0x07) << 3; - if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; - if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; - if(SiS_Pr->SiS_VBType & VB_SISVB) { - /* Don't check Part1Port,0x00 -> is not being set if LCDA! */ - /* We check SR06 instead here: */ - if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { - if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80; - } - } else { - if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80; - } - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x07,temp); /* Part1_1Ah */ - - tempbx = push2; /* BPLVDEE */ - - tempcx = SiS_Pr->SiS_LCDVDES; /* NPLVDES */ - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) { - if(resinfo == SIS_RI_800x600) tempcx++; - } - } - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) { - tempbx = tempcx = SiS_Pr->SiS_VGAVDE; - tempbx--; - } - - temp = ((tempbx >> 8) & 0x07) << 3; - temp = temp | ((tempcx >> 8) & 0x07); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); /* Part1_1Dh */ - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,temp); /* Part1_1Ch */ - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,temp); /* Part1_1Bh */ - - tempeax = SiS_Pr->SiS_VGAVDE << 18; - tempebx = SiS_Pr->SiS_VDE; - temp = (USHORT)(tempeax % tempebx); - tempeax = tempeax / tempebx; - if(temp) tempeax++; - tempvcfact = tempeax; - - temp = (USHORT)(tempeax & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); - - temp = (USHORT)((tempeax & 0x00FF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); - - temp = (USHORT)((tempeax & 0x00030000) >> 16); - if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); - - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { - temp = (USHORT)(tempeax & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp); - temp = (USHORT)((tempeax & 0x00FF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp); - temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6); - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp); - temp = 0; - if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08; - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp); - } - - tempeax = SiS_Pr->SiS_VGAHDE << 16; - tempebx = SiS_Pr->SiS_HDE; - temp = tempeax % tempebx; - tempeax /= tempebx; - if(temp) tempeax++; - if(tempebx == SiS_Pr->SiS_VGAHDE) tempeax = 0xFFFF; - tempecx = tempeax; - tempeax = ((SiS_Pr->SiS_VGAHDE << 16) / tempecx) - 1; - tempecx = (tempecx << 16) | (tempeax & 0xFFFF); - temp = (USHORT)(tempecx & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); /* Part1_1Fh */ - - tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact; - tempbx = (USHORT)(tempeax & 0x0FFFF); - - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--; - - if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempbx = 1; - - temp = ((tempbx >> 8) & 0x07) << 3; - temp = temp | ((tempecx >> 8) & 0x07); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); /* Part1_20h */ - - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,temp); /* Part1_21h */ - - tempecx >>= 16; /* BPLHCFACT */ - if(modeflag & HalfDCLK) tempecx >>= 1; - temp = (USHORT)((tempecx & 0x0000FF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); /* Part1_22h */ - - temp = (USHORT)(tempecx & 0x000000FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); + USHORT temp; - if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) { - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B); + temp = 0x04; + if(HwInfo->jChipType >= SIS_661) { + if((SiS_GetReg(SiS_Pr->SiS_P3d4,0x5c) & 0xf8) == 0x80) temp = 0x44; } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3f,temp); } -#endif /* SIS 315 */ +#endif static USHORT SiS_GetVGAHT2(SiS_Private *SiS_Pr) @@ -5552,31 +5256,37 @@ return((USHORT) tempax); } -/******* Set Part 1 / SiS bridge *********/ +/* Set Part 1 / SiS bridge slave mode */ static void SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex, PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex) { USHORT push1,push2; USHORT tempax,tempbx,tempcx,temp; - USHORT resinfo,modeflag; + USHORT resinfo,modeflag,xres=0; unsigned char p1_7, p1_8; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; + xres = SiS_Pr->CHDisplay; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - resinfo = 0; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes; } /* The following is only done if bridge is in slave mode: */ + if((HwInfo->jChipType >= SIS_661) && (ModeNo > 0x13)) { + if(xres >= 1600) { + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04); + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff); /* set MAX HT */ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) modeflag |= Charx8Dot; @@ -5637,21 +5347,20 @@ } else { if(!(modeflag & HalfDCLK)) { temp -= 4; - if((SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) && - (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200)) { + if((SiS_Pr->SiS_LCDResInfo != Panel_1280x960) && + (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200)) { if(SiS_Pr->SiS_VGAHDE >= 800) { temp -= 7; if(HwInfo->jChipType < SIS_315H) { - /* 650/301LV(x) does not do this, 630/301B, 300/301LV do */ if(SiS_Pr->SiS_ModeType == ModeEGA) { if(SiS_Pr->SiS_VGAVDE == 1024) { temp += 15; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp += 7; } } } - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { if(SiS_Pr->SiS_VGAHDE >= 1280) { if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28; } @@ -5715,6 +5424,10 @@ p1_7 = 0xab; } } + } else { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) { + if(modeflag & HalfDCLK) p1_7 = 0x30; + } } } @@ -5737,7 +5450,7 @@ else if(tempbx == 525) tempbx = 480; push2 = tempbx; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { if (tempbx == 350) tempbx += 5; else if(tempbx == 480) tempbx += 5; @@ -5783,7 +5496,7 @@ tempbx += (tempax << 1); } } else if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) { + if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) { tempbx += (tempax << 1); } } @@ -5860,521 +5573,465 @@ } } SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* 0x1A SR0E */ + + temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp); } -/*********** Set Part 1 / LVDS ***********/ +/* Setup panel link + * This is used for LVDS, LCDA and Chrontel TV output + * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA + */ static void SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, - PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) + PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) { - USHORT modeflag, resinfo; - USHORT push1, push2, tempax, tempbx, tempcx, temp; + USHORT modeflag,resinfo; + USHORT push2,tempax,tempbx,tempcx,temp; + ULONG tempeax=0,tempebx,tempecx,tempvcfact=0; + BOOLEAN islvds = FALSE, issis = FALSE, chkdclkfirst = FALSE; +#ifdef SIS300 + USHORT crt2crtc; +#endif #ifdef SIS315H USHORT pushcx; #endif - ULONG tempeax=0, tempebx, tempecx, tempvcfact=0; - - /* This is not supported on LVDS */ - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return; - if(SiS_Pr->UseCustomMode) return; if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; +#ifdef SIS300 + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; +#endif + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; +#ifdef SIS300 + crt2crtc = 0; +#endif } else { modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; +#ifdef SIS300 + crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; +#endif } - /* Set up Panel Link */ + /* is lvds if really LVDS, or SiS 301B-DH with external LVDS transmitter */ + if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || + ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBType & VB_NoLCD))) { + islvds = TRUE; + } - /* 1. Horizontal setup */ + /* is really sis if sis bridge, but not 301B-DH */ + if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { + issis = TRUE; + } - tempax = SiS_Pr->SiS_LCDHDES; - - if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { - if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) && - (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { - tempax -= 8; + if((HwInfo->jChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { + chkdclkfirst = TRUE; } } - tempcx = SiS_Pr->SiS_HT; /* Horiz. Total */ - - tempbx = SiS_Pr->SiS_HDE; /* Horiz. Display End */ - - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) { - tempbx >>= 1; - } - - if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { - tempbx = SiS_Pr->PanelXRes; - } else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - tempbx = SiS_Pr->PanelXRes; - if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) { - tempbx = 800; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) { - tempbx = 1024; +#ifdef SIS315H + if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) { + if(IS_SIS330) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } else if(IS_SIS740) { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10); + } + } else { + if(islvds) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00); + } else if(SiS_Pr->SiS_VBType & VB_SISVB) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f); + if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20); } } } } } - tempcx = (tempcx - tempbx) >> 2; /* HT-HDE / 4 */ - - push1 = tempax; - - tempax += tempbx; - - if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT; +#endif - push2 = tempax; + /* Horizontal */ - if((!SiS_Pr->SiS_IF_DEF_FSTN) && - (!SiS_Pr->SiS_IF_DEF_DSTN) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1366) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1024) && - (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { - if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 0x0028; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) tempcx = 0x0018; - else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) { - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempcx = 0x0017; /* A901; sometimes 0x0018; */ - } else { - tempcx = 0x0017; -#ifdef TWNEWPANEL - tempcx = 0x0018; -#endif - } - } else { - tempcx = 0x0018; - } - } - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) tempcx = 0x0028; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0030; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0040; + tempax = SiS_Pr->SiS_LCDHDES; + if(islvds) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) && + (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) { + tempax -= 8; } - } + } } } - tempcx += tempax; /* lcdhrs */ - if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT; + temp = (tempax & 0x0007); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* BPLHDESKEW[2:0] */ + temp = (tempax >> 3) & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* BPLHDESKEW[10:3] */ - tempax = tempcx >> 3; /* BPLHRS */ - temp = tempax & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* Part1_14h; Panel Link Horizontal Retrace Start */ - - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - temp = (tempax & 0x00FF) + 2; - } else { - temp = (tempax & 0x00FF) + 10; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if((!SiS_Pr->SiS_IF_DEF_DSTN) && - (!SiS_Pr->SiS_IF_DEF_FSTN) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1366) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1024) && - (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - temp += 6; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) { - temp++; - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) { - temp += 7; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) { - temp -= 0x14; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x768) { - temp -= 10; - } - } - } - } - } - } - } + tempbx = SiS_Pr->SiS_HDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) || + (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) { + tempbx >>= 1; + } + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempbx = SiS_Pr->PanelXRes; } } - temp &= 0x1F; - temp |= ((tempcx & 0x0007) << 5); -#if 0 - if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20; /* WRONG? BIOS loads cl, not ah */ -#endif - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* Part1_15h; Panel Link Horizontal Retrace End/Skew */ + tempax += tempbx; + if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT; - tempbx = push2; - tempcx = push1; /* lcdhdes */ + temp = tempax; + if(temp & 0x07) temp += 8; + temp >>= 3; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* BPLHDEE */ - temp = (tempcx & 0x0007); /* BPLHDESKEW */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp); /* Part1_1Ah; Panel Link Vertical Retrace Start (2:0) */ + tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2; - tempcx >>= 3; /* BPLHDES */ - temp = (tempcx & 0x00FF); -#if 0 /* Not 550 FSTN */ - if(HwInfo->jChipType >= SIS_315H) { - if(ModeNo == 0x5b) temp--; */ - } -#endif - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp); /* Part1_16h; Panel Link Horizontal Display Enable Start */ - - if((HwInfo->jChipType < SIS_315H) || - (SiS_Pr->SiS_IF_DEF_FSTN) || - (SiS_Pr->SiS_IF_DEF_DSTN)) { - if(tempbx & 0x07) tempbx += 8; - } - tempbx >>= 3; /* BPLHDEE */ - temp = tempbx & 0x00FF; -#if 0 /* Not 550 FSTN */ - if(HwInfo->jChipType >= SIS_315H) { - if(ModeNo == 0x5b) temp--; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelHRS != 999) tempcx = SiS_Pr->PanelHRS; + } } -#endif - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp); /* Part1_17h; Panel Link Horizontal Display Enable End */ - /* 2. Vertical setup */ + tempcx += tempax; + if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT; - if(HwInfo->jChipType < SIS_315H) { - tempcx = SiS_Pr->SiS_VGAVT; - tempbx = SiS_Pr->SiS_VGAVDE; - if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) && (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - tempbx = SiS_Pr->PanelYRes; + temp = (tempcx >> 3) & 0x00FF; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + switch(ModeNo) { + case 0x04: + case 0x05: + case 0x0d: temp = 0x56; break; + case 0x10: temp = 0x60; break; + case 0x13: temp = 0x5f; break; + case 0x40: + case 0x41: + case 0x4f: + case 0x43: + case 0x44: + case 0x62: + case 0x56: + case 0x53: + case 0x5d: + case 0x5e: temp = 0x54; break; } - } + } } - tempcx -= tempbx; + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp); /* BPLHRS */ + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + temp += 2; + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + temp += 8; + if(SiS_Pr->PanelHRE != 999) { + temp = tempcx + SiS_Pr->PanelHRE; + if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT; + temp >>= 3; + } + } } else { - - tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE; /* VGAVT-VGAVDE */ - + temp += 10; } - tempbx = SiS_Pr->SiS_LCDVDES; /* VGAVDES */ - push1 = tempbx; + temp &= 0x1F; + temp |= ((tempcx & 0x07) << 5); +#if 0 + if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20; /* WRONG? BIOS loads cl, not ah */ +#endif + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp); /* BPLHRE */ - tempax = SiS_Pr->SiS_VGAVDE; + /* Vertical */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - tempax = 600; - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) { - tempax = 768; - } - } - } else if( (SiS_Pr->SiS_IF_DEF_TRUMPION == 0) && - (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) && - ((SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) || - (SiS_Pr->SiS_IF_DEF_FSTN) || - (SiS_Pr->SiS_IF_DEF_DSTN)) ) { + tempax = SiS_Pr->SiS_VGAVDE; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { tempax = SiS_Pr->PanelYRes; } } - tempbx += tempax; + tempbx = SiS_Pr->SiS_LCDVDES + tempax; if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; push2 = tempbx; - tempcx >>= 1; - - if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && - (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1366) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1024) && - (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) { - tempcx = 0x0017; - } else if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 0x0003; - else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)) tempcx = 0x0003; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0001; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0001; - else tempcx = 0x0057; - } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 0x0001; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) tempcx = 0x0001; - else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)) { - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempcx = 0x0002; /* A901; sometimes 0x0003; */ - } else { - tempcx = 0x0002; -#ifdef TWNEWPANEL - tempcx = 0x0003; -#endif - } - } else tempcx = 0x0003; - } - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) tempcx = 0x0003; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0001; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0001; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0001; - else tempcx = 0x0057; + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE; + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes; } } } + if(islvds) tempcx >>= 1; + else tempcx >>= 2; - tempbx += tempcx; /* BPLVRS */ - - if((HwInfo->jChipType < SIS_315H) || - (SiS_Pr->SiS_IF_DEF_FSTN) || - (SiS_Pr->SiS_IF_DEF_DSTN)) { - tempbx++; + if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) && + (SiS_Pr->PanelVRS != 999) ) { + tempcx = SiS_Pr->PanelVRS; + tempbx += tempcx; + if(issis) tempbx++; + } else { + tempbx += tempcx; + if(HwInfo->jChipType < SIS_315H) tempbx++; + else if(issis) tempbx++; } - if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; + if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT; /* BPLVRS */ temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); /* Part1_18h; Panel Link Vertical Retrace Start */ + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x10) temp = 0xa9; + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp); tempcx >>= 3; + tempcx++; - if((!(SiS_Pr->SiS_LCDInfo & LCDPass11)) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1366) && - (SiS_Pr->SiS_CustomT != CUT_BARCO1024) && - (SiS_Pr->SiS_CustomT != CUT_PANEL848)) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if( (HwInfo->jChipType < SIS_315H) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) ) tempcx = 0x0001; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) tempcx = 0x0002; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempcx = 0x0002; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) tempcx = 0x0003; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) tempcx = 0x0005; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) tempcx = 0x0005; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) tempcx = 0x0011; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0005; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0002; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0011; - else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempcx = 0x0004; /* A901; Other BIOS sets 0x0005; */ - } else { - tempcx = 0x0004; -#ifdef TWNEWPANEL - tempcx = 0x0005; -#endif - } - } else { - tempcx = 0x0005; - } - } + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if(SiS_Pr->PanelVRE != 999) tempcx = SiS_Pr->PanelVRE; } } - tempcx = tempcx + tempbx + 1; /* BPLVRE */ + tempcx += tempbx; temp = tempcx & 0x000F; - if(SiS_Pr->SiS_IF_DEF_FSTN || - SiS_Pr->SiS_IF_DEF_DSTN || - (SiS_Pr->SiS_CustomT == CUT_BARCO1366) || - (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || - (SiS_Pr->SiS_CustomT == CUT_PANEL848)) { - temp |= 0x30; - } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; Panel Link Vertical Retrace End (3:0); Misc. */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); /* BPLVRE */ - temp = ((tempbx & 0x0700) >> 8) << 3; /* BPLDESKEW =0 */ + temp = ((tempbx >> 8) & 0x07) << 3; if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { if(SiS_Pr->SiS_HDE != 640) { - if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; } - } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; - if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; - if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { - if(HwInfo->jChipType >= SIS_315H) { - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) { - temp |= 0x80; + } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40; + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) temp |= 0x40; + tempbx = 0x87; + if((HwInfo->jChipType >= SIS_315H) || + (HwInfo->jChipRevision >= 0x30)) { + tempbx = 0x07; + if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03) temp |= 0x80; + } + /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit mutliplexed) via VGA2 */ + if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80; + } else { + if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80; + } + } + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp); + + tempbx = push2; /* BPLVDEE */ + + tempcx = SiS_Pr->SiS_LCDVDES; /* BPLVDES */ + + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + switch(SiS_Pr->SiS_LCDResInfo) { + case Panel_640x480: + tempbx = SiS_Pr->SiS_VGAVDE - 1; + tempcx = SiS_Pr->SiS_VGAVDE; + break; + case Panel_800x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_800x600) tempcx++; } - } else { - if( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) { - if(HwInfo->jChipRevision >= 0x30) { - temp |= 0x80; + break; + case Panel_1024x600: + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x600) tempcx++; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(resinfo == SIS_RI_800x600) tempcx++; } - } + } + break; + case Panel_1024x768: + if(HwInfo->jChipType < SIS_315H) { + if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + if(resinfo == SIS_RI_1024x768) tempcx++; + } + } + break; } } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp); /* Part1_1Ah; Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */ - if (HwInfo->jChipType < SIS_315H) { + temp = ((tempbx >> 8) & 0x07) << 3; + temp = temp | ((tempcx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); + /* if(SiS_Pr->SiS_IF_DEF_FSTN) tempbx++; */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx); -#ifdef SIS300 /* 300 series */ + /* Vertical scaling */ - tempeax = SiS_Pr->SiS_VGAVDE << 6; - temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE); - tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE; - if(temp != 0) tempeax++; - tempebx = tempeax; /* BPLVCFACT */ + if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) { - tempebx = 0x003F; - } +#ifdef SIS300 /* 300 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 6; + temp = (tempeax % (ULONG)SiS_Pr->SiS_VDE); + tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE; + if(temp) tempeax++; - temp = (USHORT)(tempebx & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* Part1_1Eh; Panel Link Vertical Scaling Factor */ + if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F; + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp); /* BPLVCFACT */ + tempvcfact = temp; #endif /* SIS300 */ } else { #ifdef SIS315H /* 315 series */ + tempeax = SiS_Pr->SiS_VGAVDE << 18; + tempebx = SiS_Pr->SiS_VDE; + temp = (tempeax % tempebx); + tempeax = tempeax / tempebx; + if(temp) tempeax++; + tempvcfact = tempeax; - if(HwInfo->jChipType == SIS_740) { - SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x03); - } else { - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,0x23); - } - - tempeax = SiS_Pr->SiS_VGAVDE << 18; - temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE); - tempeax = tempeax / SiS_Pr->SiS_VDE; - if(temp != 0) tempeax++; - tempebx = tempeax; /* BPLVCFACT */ - tempvcfact = tempeax; - temp = (USHORT)(tempebx & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); /* Part1_37h; Panel Link Vertical Scaling Factor */ - temp = (USHORT)((tempebx & 0x00FF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); /* Part1_36h; Panel Link Vertical Scaling Factor */ - temp = (USHORT)((tempebx & 0x00030000) >> 16); - temp &= 0x03; - if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); /* Part1_35h; Panel Link Vertical Scaling Factor */ - -#endif /* SIS315H */ - - } - - tempbx = push2; /* BPLVDEE */ - tempcx = push1; - - push1 = temp; - - if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - if(!SiS_Pr->SiS_IF_DEF_FSTN && !SiS_Pr->SiS_IF_DEF_DSTN) { - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) { - if(resinfo == SIS_RI_1024x600) tempcx++; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(resinfo == SIS_RI_800x600) tempcx++; - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) { - if(resinfo == SIS_RI_800x600) tempcx++; - if(resinfo == SIS_RI_1024x768) tempcx++; /* Doesnt make sense anyway... */ - } else if(resinfo == SIS_RI_1024x768) tempcx++; - } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) { - if(resinfo == SIS_RI_800x600) tempcx++; - } - } - } - } + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp); + temp = (USHORT)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp); + temp = (USHORT)((tempeax & 0x00030000) >> 16); + if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp); - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) { - if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { - tempcx = SiS_Pr->SiS_VGAVDE; - tempbx = SiS_Pr->SiS_VGAVDE - 1; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { + temp = (USHORT)(tempeax & 0x00FF); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp); + temp = (USHORT)((tempeax & 0x00FF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp); + temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6); + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp); + temp = 0; + if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp); } - } - - temp = ((tempbx & 0x0700) >> 8) << 3; - temp |= ((tempcx & 0x0700) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp); /* Part1_1Dh; Vertical Display Overflow; Control Signal */ - - temp = tempbx & 0x00FF; - /* if(SiS_Pr->SiS_IF_DEF_FSTN) temp++; */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,temp); /* Part1_1Ch; Panel Link Vertical Display Enable End */ +#endif - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,temp); /* Part1_1Bh; Panel Link Vertical Display Enable Start */ + } - /* 3. Additional horizontal setup (scaling, etc) */ + /* Horizontal scaling */ - tempecx = SiS_Pr->SiS_VGAHDE; - if(HwInfo->jChipType >= SIS_315H) { - if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { - if(modeflag & HalfDCLK) tempecx >>= 1; - } + tempeax = SiS_Pr->SiS_VGAHDE; /* 1f = ( (VGAHDE * 65536) / ( (VGAHDE * 65536) / HDE ) ) - 1*/ + if(chkdclkfirst) { + if(modeflag & HalfDCLK) tempeax >>= 1; } - tempebx = SiS_Pr->SiS_HDE; - if(tempecx == tempebx) tempeax = 0xFFFF; - else { - tempeax = tempecx; - tempeax <<= 16; - temp = (USHORT)(tempeax % tempebx); - tempeax = tempeax / tempebx; + tempebx = tempeax << 16; + if(SiS_Pr->SiS_HDE == tempeax) { + tempecx = 0xFFFF; + } else { + tempecx = tempebx / SiS_Pr->SiS_HDE; if(HwInfo->jChipType >= SIS_315H) { - if(temp) tempeax++; + if(tempebx % SiS_Pr->SiS_HDE) tempecx++; } } - tempecx = tempeax; if(HwInfo->jChipType >= SIS_315H) { - tempeax = SiS_Pr->SiS_VGAHDE; - if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) { - if(modeflag & HalfDCLK) tempeax >>= 1; - } - tempeax <<= 16; - tempeax = (tempeax / tempecx) - 1; + tempeax = (tempebx / tempecx) - 1; } else { tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1; } - tempecx <<= 16; - tempecx |= (tempeax & 0xFFFF); + tempecx = (tempecx << 16) | (tempeax & 0xFFFF); temp = (USHORT)(tempecx & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); /* Part1_1Fh; Panel Link DDA Operational Number in each horiz. line */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp); - tempbx = SiS_Pr->SiS_VDE; if(HwInfo->jChipType >= SIS_315H) { tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact; - tempbx = (USHORT)(tempeax & 0x0FFFF); + tempbx = (USHORT)(tempeax & 0xFFFF); } else { tempeax = SiS_Pr->SiS_VGAVDE << 6; - tempbx = push1 & 0x3f; + tempbx = tempvcfact & 0x3f; if(tempbx == 0) tempbx = 64; tempeax /= tempbx; - tempbx = (USHORT)(tempeax & 0x0FFFF); + tempbx = (USHORT)(tempeax & 0xFFFF); } - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--; if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) { if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1; - else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempbx = 1; + else if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) tempbx = 1; } - temp = ((tempbx & 0xFF00) >> 8) << 3; - temp |= (USHORT)((tempecx & 0x0700) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); /* Part1_20h; Overflow register */ - - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,temp); /* Part1_21h; Panel Link Vertical Accumulator Register */ + temp = ((tempbx >> 8) & 0x07) << 3; + temp = temp | ((tempecx >> 8) & 0x07); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx); - tempecx >>= 16; /* BPLHCFACT */ - if((HwInfo->jChipType < SIS_315H) || (SiS_Pr->SiS_IF_DEF_FSTN) || (SiS_Pr->SiS_IF_DEF_DSTN)) { + tempecx >>= 16; /* BPLHCFACT */ + if(!chkdclkfirst) { if(modeflag & HalfDCLK) tempecx >>= 1; } temp = (USHORT)((tempecx & 0xFF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); /* Part1_22h; Panel Link Horizontal Scaling Factor High */ - + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp); temp = (USHORT)(tempecx & 0x00FF); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); /* Part1_22h; Panel Link Horizontal Scaling Factor Low */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp); - /* 630/301B and 630/LVDS do something for 640x480 panels here */ +#ifdef SIS315H + if(HwInfo->jChipType >= SIS_315H) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20); + } + } else { + if(islvds) { + if(HwInfo->jChipType == SIS_740) { + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03); + } else { + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23); + } + } + } + } +#endif + +#ifdef SIS300 + if(SiS_Pr->SiS_IF_DEF_TRUMPION) { + int i; + UCHAR TrumpMode13[4] = { 0x01, 0x10, 0x2c, 0x00 }; + UCHAR TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 }; + UCHAR TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 }; + + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf); + for(i=0; i<5; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &SiS300_TrumpionData[crt2crtc][0]); + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(ModeNo == 0x13) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]); + } + } else if(ModeNo == 0x10) { + for(i=0; i<4; i++) { + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_1[0]); + SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_2[0]); + } + } + } + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40); + } +#endif #ifdef SIS315H if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) { @@ -6384,10 +6041,10 @@ SiS_SetReg(SiS_Pr->SiS_Part1Port,0x28,0x87); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B); - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03); tempax = SiS_Pr->SiS_HDE; /* Blps = lcdhdee(lcdhdes+HDE) + 64 */ - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; tempax += 64; temp = tempax & 0x00FF; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,temp); @@ -6401,8 +6058,8 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00); tempax = SiS_Pr->SiS_VDE; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; tempax >>= 1; temp = tempax & 0x00FF; SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,temp); @@ -6410,8 +6067,8 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp); tempeax = SiS_Pr->SiS_HDE; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempeax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempeax >>= 1; tempeax <<= 2; /* BDxFIFOSTOP = (HDE*4)/128 */ tempebx = 128; temp = (USHORT)(tempeax % tempebx); @@ -6425,8 +6082,8 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00); tempax = SiS_Pr->SiS_HDE; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; tempax >>= 4; /* BDxWadroff = HDE*4/8/8 */ pushcx = tempax; temp = tempax & 0x00FF; @@ -6435,8 +6092,8 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp); tempax = SiS_Pr->SiS_VDE; /* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */ - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 || - SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1; + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 || + SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1; tempeax = (tempax * pushcx); tempebx = 0x00100000 + tempeax; temp = (USHORT)tempebx & 0x000000FF; @@ -6478,496 +6135,422 @@ } } #endif /* SIS315H */ - } -/************** Set Part 1 ***************/ +/* Set Part 1 */ static void SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT temp=0, tempax=0, tempbx=0, tempcx=0; - USHORT pushbx=0, CRT1Index=0; + USHORT pushbx=0, CRT1Index=0, modeflag, resinfo=0; #ifdef SIS315H USHORT tempbl=0; #endif - USHORT modeflag, resinfo=0; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + return; + } if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - -#ifdef SIS315H - SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); - SiS_SetGroup1_LCDA(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); -#endif - - } else { + SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - if( (HwInfo->jChipType >= SIS_315H) && + if( ! ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1) && - (SiS_Pr->SiS_VBInfo & SetInSlaveMode) ) { + (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) { - SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); - - } else { - - SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, - RefreshRateTableIndex, HwInfo); - - if (HwInfo->jChipType < SIS_315H ) { + if(HwInfo->jChipType < SIS_315H ) { #ifdef SIS300 - SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo); + SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo); #endif - } else { + } else { #ifdef SIS315H - SiS_SetCRT2FIFO_310(SiS_Pr); + SiS_SetCRT2FIFO_310(SiS_Pr, HwInfo); #endif - } - - SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + } - /* 1. Horizontal setup */ + /* 1. Horizontal setup */ - if(HwInfo->jChipType < SIS_315H ) { + if(HwInfo->jChipType < SIS_315H ) { #ifdef SIS300 /* ------------- 300 series --------------*/ - temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ + temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF; /* BTVGA2HT 0x08,0x09 */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ - temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp); /* CRT2 Horizontal Total Overflow [7:4] */ - temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ + temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF; /* BTVGA2HDEE 0x0A,0x0C */ + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ - pushbx = SiS_Pr->SiS_VGAHDE + 12; /* bx BTVGA@HRS 0x0B,0x0C */ - tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; - tempbx = pushbx + tempcx; - tempcx <<= 1; - tempcx += tempbx; - - if(SiS_Pr->SiS_VBType & VB_SISVB) { - - if(SiS_Pr->UseCustomMode) { - tempbx = SiS_Pr->CHSyncStart + 12; - tempcx = SiS_Pr->CHSyncEnd + 12; - } + pushbx = SiS_Pr->SiS_VGAHDE + 12; /* bx BTVGA2HRS 0x0B,0x0C */ + tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2; + tempbx = pushbx + tempcx; + tempcx <<= 1; + tempcx += tempbx; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { - unsigned char cr4, cr14, cr5, cr15; - if(SiS_Pr->UseCustomMode) { - cr4 = SiS_Pr->CCRT1CRTC[4]; - cr14 = SiS_Pr->CCRT1CRTC[14]; - cr5 = SiS_Pr->CCRT1CRTC[5]; - cr15 = SiS_Pr->CCRT1CRTC[15]; - } else { - cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; - cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; - cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; - cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; - } - tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 1) << 3; - tempcx = (((cr5 & 0x1F) | ((cr15 & 0x04) << (6-2))) - 1) << 3; - } - - if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == SIS_RI_1024x768)){ - if(!(SiS_Pr->SiS_TVMode & TVSetPAL)){ - tempbx = 1040; - tempcx = 1042; - } - } - } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart + 12; + tempcx = SiS_Pr->CHSyncEnd + 12; + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr4, cr14, cr5, cr15; + if(SiS_Pr->UseCustomMode) { + cr4 = SiS_Pr->CCRT1CRTC[4]; + cr14 = SiS_Pr->CCRT1CRTC[14]; + cr5 = SiS_Pr->CCRT1CRTC[5]; + cr15 = SiS_Pr->CCRT1CRTC[15]; + } else { + cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; + cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; + cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; + } + tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 1) << 3; + tempcx = (((cr5 & 0x1F) | ((cr15 & 0x04) << (6-2))) - 1) << 3; + } + + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + tempbx = 1040; + tempcx = 1044; + } + + } + + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); /* CRT2 Horizontal Retrace Start */ - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); /* CRT2 Horizontal Retrace Start */ #endif /* SIS300 */ - } else { + } else { #ifdef SIS315H /* ------------------- 315/330 series --------------- */ - tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */ - if(modeflag & HalfDCLK) { - if(SiS_Pr->SiS_VBType & VB_SISVB) { - tempcx >>= 1; - } else { - tempax = SiS_Pr->SiS_VGAHDE >> 1; - tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempcx = SiS_Pr->SiS_HT - tempax; - } - } - } - tempcx--; + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HT 0x08,0x09 */ + if(modeflag & HalfDCLK) { + if(SiS_Pr->SiS_VBType & VB_SISVB) { + tempcx >>= 1; + } else { + tempax = SiS_Pr->SiS_VGAHDE >> 1; + tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + tempcx = SiS_Pr->SiS_HT - tempax; + } + } + } + tempcx--; - temp = tempcx & 0xff; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ + temp = tempcx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp); /* CRT2 Horizontal Total */ - temp = ((tempcx & 0xff00) >> 8) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp); /* CRT2 Horizontal Total Overflow [7:4] */ + temp = ((tempcx & 0xff00) >> 8) << 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp); /* CRT2 Horizontal Total Overflow [7:4] */ - tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HDEE 0x0A,0x0C */ - tempbx = SiS_Pr->SiS_VGAHDE; - tempcx -= tempbx; - tempcx >>= 2; - if(modeflag & HalfDCLK) { - tempbx >>= 1; - tempcx >>= 1; - } - tempbx += 16; + tempcx = SiS_Pr->SiS_VGAHT; /* BTVGA2HDEE 0x0A,0x0C */ + tempbx = SiS_Pr->SiS_VGAHDE; + tempcx -= tempbx; + tempcx >>= 2; + if(modeflag & HalfDCLK) { + tempbx >>= 1; + tempcx >>= 1; + } + tempbx += 16; - temp = tempbx & 0xff; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp); /* CRT2 Horizontal Display Enable End */ - pushbx = tempbx; - tempcx >>= 1; - tempbx += tempcx; - tempcx += tempbx; - - if(SiS_Pr->SiS_VBType & VB_SISVB) { - - if(HwInfo->jChipType >= SIS_661) { - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) { - if(resinfo == SIS_RI_1280x1024) { - tempcx = 0x30; - } else if(resinfo == SIS_RI_1600x1200) { - tempcx = 0xff; - } - } - } + pushbx = tempbx; + tempcx >>= 1; + tempbx += tempcx; + tempcx += tempbx; - if(SiS_Pr->UseCustomMode) { - tempbx = SiS_Pr->CHSyncStart + 16; - tempcx = SiS_Pr->CHSyncEnd + 16; - tempax = SiS_Pr->SiS_VGAHT; - if(modeflag & HalfDCLK) tempax >>= 1; - tempax--; - if(tempcx > tempax) tempcx = tempax; - } + if(SiS_Pr->SiS_VBType & VB_SISVB) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { - unsigned char cr4, cr14, cr5, cr15; - if(SiS_Pr->UseCustomMode) { - cr4 = SiS_Pr->CCRT1CRTC[4]; - cr14 = SiS_Pr->CCRT1CRTC[14]; - cr5 = SiS_Pr->CCRT1CRTC[5]; - cr15 = SiS_Pr->CCRT1CRTC[15]; - } else { - cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; - cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; - cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; - cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; - } - tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ - tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ - tempcx &= 0x00FF; - tempcx |= (tempbx & 0xFF00); - tempbx += 16; - tempcx += 16; - tempax = SiS_Pr->SiS_VGAHT; - if(modeflag & HalfDCLK) tempax >>= 1; - tempax--; - if(tempcx > tempax) tempcx = tempax; - } - - if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { - tempbx = 1040; - tempcx = 1042; - } + if(HwInfo->jChipType >= SIS_661) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) { + if(resinfo == SIS_RI_1280x1024) { + tempcx = 0x30; + } else if(resinfo == SIS_RI_1600x1200) { + tempcx = 0xff; + } + } + } - } + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart + 16; + tempcx = SiS_Pr->CHSyncEnd + 16; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } - temp = tempbx & 0xff; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); /* CRT2 Horizontal Retrace Start */ -#endif /* SIS315H */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr4, cr14, cr5, cr15; + if(SiS_Pr->UseCustomMode) { + cr4 = SiS_Pr->CCRT1CRTC[4]; + cr14 = SiS_Pr->CCRT1CRTC[14]; + cr5 = SiS_Pr->CCRT1CRTC[5]; + cr15 = SiS_Pr->CCRT1CRTC[15]; + } else { + cr4 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4]; + cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14]; + cr5 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5]; + cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15]; + } + tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; /* (VGAHRS-3)*8 */ + tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; /* (VGAHRE-3)*8 */ + tempcx &= 0x00FF; + tempcx |= (tempbx & 0xFF00); + tempbx += 16; + tempcx += 16; + tempax = SiS_Pr->SiS_VGAHT; + if(modeflag & HalfDCLK) tempax >>= 1; + tempax--; + if(tempcx > tempax) tempcx = tempax; + } - } /* 315/330 series */ + if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) { + tempbx = 1040; + tempcx = 1044; /* HWCursor bug! */ + } - /* The following is done for all bridge/chip types/series */ + } - tempax = tempbx & 0xFF00; - tempbx = pushbx; - tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4); - tempax |= (tempbx & 0xFF00); - temp = (tempax & 0xFF00) >> 8; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); /* Overflow */ + temp = tempbx & 0xff; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp); /* CRT2 Horizontal Retrace Start */ +#endif /* SIS315H */ - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp); /* CRT2 Horizontal Retrace End */ + } /* 315/330 series */ - /* 2. Vertical setup */ + tempax = tempbx & 0xFF00; + tempbx = pushbx; + tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4); + tempax |= (tempbx & 0xFF00); + temp = (tempax & 0xFF00) >> 8; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp); - tempcx = SiS_Pr->SiS_VGAVT - 1; - temp = tempcx & 0x00FF; + temp = tempcx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp); /* CRT2 Horizontal Retrace End */ - if(HwInfo->jChipType < SIS_661) { - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { - temp--; - } - } - } else { - temp--; + /* 2. Vertical setup */ + + tempcx = SiS_Pr->SiS_VGAVT - 1; + temp = tempcx & 0x00FF; + + if(HwInfo->jChipType < SIS_661) { + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { + temp--; + } } - } else if(HwInfo->jChipType >= SIS_315H) { - temp--; - } + } else { + temp--; + } + } else if(HwInfo->jChipType >= SIS_315H) { + temp--; } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); /* CRT2 Vertical Total */ + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp); /* CRT2 Vertical Total */ - tempbx = SiS_Pr->SiS_VGAVDE - 1; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,temp); /* CRT2 Vertical Display Enable End */ - - temp = ((tempbx & 0xFF00) << 3) >> 8; - temp |= ((tempcx & 0xFF00) >> 8); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp); /* Overflow (and HWCursor Test Mode) */ - - if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { - tempbx++; - tempax = tempbx; - tempcx++; - tempcx -= tempax; - tempcx >>= 2; - tempbx += tempcx; - if(tempcx < 4) tempcx = 4; - tempcx >>= 2; - tempcx += tempbx; - tempcx++; - } else { - tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ - tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ - } + tempbx = SiS_Pr->SiS_VGAVDE - 1; + temp = tempbx & 0x00FF; + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,temp); /* CRT2 Vertical Display Enable End */ - if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = ((tempbx & 0xFF00) << 3) >> 8; + temp |= ((tempcx & 0xFF00) >> 8); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp); /* Overflow (and HWCursor Test Mode) */ + + if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) { + tempbx++; + tempax = tempbx; + tempcx++; + tempcx -= tempax; + tempcx >>= 2; + tempbx += tempcx; + if(tempcx < 4) tempcx = 4; + tempcx >>= 2; + tempcx += tempbx; + tempcx++; + } else { + tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1; /* BTVGA2VRS 0x10,0x11 */ + tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1; /* BTVGA2VRE 0x11 */ + } + if(SiS_Pr->SiS_VBType & VB_SISVB) { + + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CVSyncStart; + tempcx = (tempcx & 0xFF00) | (SiS_Pr->CVSyncEnd & 0x00FF); + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { + unsigned char cr8, cr7, cr13, cr9; if(SiS_Pr->UseCustomMode) { - tempbx = SiS_Pr->CVSyncStart; - tempcx = (tempcx & 0xFF00) | (SiS_Pr->CVSyncEnd & 0x00FF); - } + cr8 = SiS_Pr->CCRT1CRTC[8]; + cr7 = SiS_Pr->CCRT1CRTC[7]; + cr13 = SiS_Pr->CCRT1CRTC[13]; + cr9 = SiS_Pr->CCRT1CRTC[9]; + } else { + cr8 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8]; + cr7 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; + cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; + cr9 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9]; + } + tempbx = cr8; + if(cr7 & 0x04) tempbx |= 0x0100; + if(cr7 & 0x80) tempbx |= 0x0200; + if(cr13 & 0x08) tempbx |= 0x0400; + tempcx = (tempcx & 0xFF00) | (cr9 & 0x00FF); + } + } + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx); /* CRT2 Vertical Retrace Start */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { - unsigned char cr8, cr7, cr13, cr9; - if(SiS_Pr->UseCustomMode) { - cr8 = SiS_Pr->CCRT1CRTC[8]; - cr7 = SiS_Pr->CCRT1CRTC[7]; - cr13 = SiS_Pr->CCRT1CRTC[13]; - cr9 = SiS_Pr->CCRT1CRTC[9]; - } else { - cr8 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8]; - cr7 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7]; - cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]; - cr9 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9]; - } - tempbx = cr8; - if(cr7 & 0x04) tempbx |= 0x0100; - if(cr7 & 0x80) tempbx |= 0x0200; - if(cr13 & 0x08) tempbx |= 0x0400; - tempcx = (tempcx & 0xFF00) | (cr9 & 0x00FF); - } - } - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp); /* CRT2 Vertical Retrace Start */ - - temp = ((tempbx & 0xFF00) >> 8) << 4; - temp |= (tempcx & 0x000F); - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp); /* CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */ + temp = ((tempbx & 0xFF00) >> 8) << 4; + temp |= (tempcx & 0x000F); + SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp); /* CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */ - /* 3. Panel compensation delay */ + /* 3. Panel delay compensation */ - if(HwInfo->jChipType < SIS_315H) { + if(HwInfo->jChipType < SIS_315H) { #ifdef SIS300 /* ---------- 300 series -------------- */ - if(SiS_Pr->SiS_VBType & VB_SISVB) { - temp = 0x20; + if(SiS_Pr->SiS_VBType & VB_SISVB) { + temp = 0x20; - if(HwInfo->jChipType == SIS_300) { - temp = 0x10; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) temp = 0x2c; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20; - } - if(SiS_Pr->SiS_VBType & VB_SIS301) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20; - } - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) temp = 0x24; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) temp = 0x2c; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; - else temp = 0x20; - } - if((ROMAddr) && (SiS_Pr->SiS_UseROM)) { - if(ROMAddr[0x220] & 0x80) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) - temp = ROMAddr[0x221]; - else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) - temp = ROMAddr[0x222]; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) - temp = ROMAddr[0x223]; - else - temp = ROMAddr[0x224]; - temp &= 0x3c; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->PDC) { - temp = SiS_Pr->PDC & 0x3c; - } - } - } else { - temp = 0x20; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) temp = 0x04; - } - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - if(ROMAddr[0x220] & 0x80) { - temp = ROMAddr[0x220] & 0x3c; - } - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->PDC) { - temp = SiS_Pr->PDC & 0x3c; - } - } + if(HwInfo->jChipType == SIS_300) { + temp = 0x10; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) temp = 0x2c; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_VBType & VB_SIS301) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20; + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) temp = 0x24; + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) temp = 0x2c; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; + else temp = 0x20; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) + temp = ROMAddr[0x221]; + else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) + temp = ROMAddr[0x222]; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) + temp = ROMAddr[0x223]; + else + temp = ROMAddr[0x224]; + temp &= 0x3c; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; + } + + } else { + temp = 0x20; + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { + if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) temp = 0x04; + } + if(SiS_Pr->SiS_UseROM) { + if(ROMAddr[0x220] & 0x80) { + temp = ROMAddr[0x220] & 0x3c; + } + } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c; } + } - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */ #endif /* SIS300 */ - } else { + } else { #ifdef SIS315H /* --------------- 315/330 series ---------------*/ - if(HwInfo->jChipType < SIS_661) { - - if(SiS_Pr->SiS_VBType & VB_SISVB) { + if(HwInfo->jChipType < SIS_661) { - temp = 0x10; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) temp = 0x2c; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) temp = 0x24; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) temp = 0x2c; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - temp = 0x08; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c; - else temp = 0x20; - } - } - if((SiS_Pr->SiS_VBType & VB_SIS301B302B) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) { - tempbl = 0x00; - if((ROMAddr) && (SiS_Pr->SiS_UseROM)) { - if(HwInfo->jChipType < SIS_330) { - if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0; - } else { - if(ROMAddr[0x1bc] & 0x80) tempbl = 0xf0; - } - } - } else { /* LV (550/301LV checks ROM byte, other LV BIOSes do not) */ - tempbl = 0xF0; - } - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - if(SiS_Pr->PDC) { - temp = SiS_Pr->PDC; - tempbl = 0; - } - } - } + if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - } else { /* LVDS */ + if(HwInfo->jChipType == SIS_740) temp = 0x03; + else temp = 0x00; - if(HwInfo->jChipType == SIS_740) { - temp = 0x03; - } else { - temp = 0x00; - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a; - tempbl = 0xF0; - if(HwInfo->jChipType == SIS_650) { - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F; - } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a; + tempbl = 0xF0; + if(HwInfo->jChipType == SIS_650) { + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F; } + } - if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) { - temp = 0x08; - tempbl = 0; - if((ROMAddr) && (SiS_Pr->SiS_UseROM)) { - if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0; - } + if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) { + temp = 0x08; + tempbl = 0; + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0; } } SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp); /* Panel Link Delay Compensation */ + } - } /* < 661 */ + } /* < 661 */ - tempax = 0; - if (modeflag & DoubleScanMode) tempax |= 0x80; - if (modeflag & HalfDCLK) tempax |= 0x40; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); + tempax = 0; + if (modeflag & DoubleScanMode) tempax |= 0x80; + if (modeflag & HalfDCLK) tempax |= 0x40; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax); #endif /* SIS315H */ - } - - } /* Slavemode */ + } - if(SiS_Pr->SiS_VBType & VB_SISVB) { + } /* Slavemode */ + if(SiS_Pr->SiS_VBType & VB_SISVB) { + if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { /* For 301BDH with LCD, we set up the Panel Link */ - if( (SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) { - - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, - HwInfo, RefreshRateTableIndex); - - } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - - SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, - HwInfo, RefreshRateTableIndex); - } - + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); + } + } else { + if(HwInfo->jChipType < SIS_315H) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex); } else { - - if(HwInfo->jChipType < SIS_315H) { - - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, - HwInfo, RefreshRateTableIndex); + if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { + if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); + } } else { - - if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { - if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, - HwInfo,RefreshRateTableIndex); - } - } else { - SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, - HwInfo,RefreshRateTableIndex); - } - + SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex); } - } - } /* LCDA */ + } } /*********************************************/ @@ -6978,9 +6561,8 @@ static UCHAR * SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; const UCHAR *tableptr = NULL; - USHORT a, b, p = 0; + USHORT a, b, p = 0; a = SiS_Pr->SiS_VGAHDE; b = SiS_Pr->SiS_HDE; @@ -6989,62 +6571,32 @@ b = SiS_Pr->SiS_VDE; } - if((ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) { - - if(a < b) { - p = ROMAddr[0x278] | (ROMAddr[0x279] << 8); - } else if(a == b) { - p = ROMAddr[0x27a] | (ROMAddr[0x27b] << 8); - } else { - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - p = ROMAddr[0x27e] | (ROMAddr[0x27f] << 8); - } else { - p = ROMAddr[0x27c] | (ROMAddr[0x27d] << 8); - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) p = ROMAddr[0x280] | (ROMAddr[0x281] << 8); - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) p = ROMAddr[0x282] | (ROMAddr[0x283] << 8); - else p = ROMAddr[0x284] | (ROMAddr[0x285] << 8); - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - p = ROMAddr[0x286] | (ROMAddr[0x287] << 8); - } - do { - if((ROMAddr[p] | ROMAddr[p+1] << 8) == a) break; - p += 0x42; - } while((ROMAddr[p] | ROMAddr[p+1] << 8) != 0xffff); - if((ROMAddr[p] | ROMAddr[p+1] << 8) == 0xffff) p -= 0x42; - } - p += 2; - return(&ROMAddr[p]); - + if(a < b) { + tableptr = SiS_Part2CLVX_1; + } else if(a == b) { + tableptr = SiS_Part2CLVX_2; } else { - - if(a < b) { - tableptr = SiS_Part2CLVX_1; - } else if(a == b) { - tableptr = SiS_Part2CLVX_2; + if(SiS_Pr->SiS_TVMode & TVSetPAL) { + tableptr = SiS_Part2CLVX_4; } else { - if(SiS_Pr->SiS_TVMode & TVSetPAL) { - tableptr = SiS_Part2CLVX_4; - } else { - tableptr = SiS_Part2CLVX_3; - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) tableptr = SiS_Part2CLVX_3; - else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tableptr = SiS_Part2CLVX_3; - else tableptr = SiS_Part2CLVX_5; - } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - tableptr = SiS_Part2CLVX_6; - } - do { - if((tableptr[p] | tableptr[p+1] << 8) == a) break; - p += 0x42; - } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff); - if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42; + tableptr = SiS_Part2CLVX_3; } - p += 2; - return((UCHAR *)&tableptr[p]); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) tableptr = SiS_Part2CLVX_3; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tableptr = SiS_Part2CLVX_3; + else tableptr = SiS_Part2CLVX_5; + + } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + tableptr = SiS_Part2CLVX_6; + } + do { + if((tableptr[p] | tableptr[p+1] << 8) == a) break; + p += 0x42; + } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff); + if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42; } + p += 2; + return((UCHAR *)&tableptr[p]); } static void @@ -7055,7 +6607,7 @@ int i, j; UCHAR temp; - if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return; + if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return; tableptr = SiS_GetGroup2CLVXPtr(SiS_Pr, 0, HwInfo); for(i = 0x80, j = 0; i <= 0xbf; i++, j++) { @@ -7072,49 +6624,97 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp); } -static void +static BOOLEAN SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex, USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex,PSIS_HW_INFO HwInfo) { - USHORT tempbx,tempal; - + + if(HwInfo->jChipType < SIS_315H) return FALSE; + if(ModeNo <= 0x13) - tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; else - tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - - tempbx = SiS_Pr->SiS_LCDResInfo; + (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 16; - else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32; + (*ResIndex) &= 0x3f; + (*CRT2Index) = 0; - if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tempbx = 100; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 101; - else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 102; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + (*CRT2Index) = 200; } - } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - tempbx = 103; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx = 104; - else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 105; - } - } - } else if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 106; + } + + if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206; } } + return(((*CRT2Index) != 0)); +} +#endif + +#ifdef SIS300 +static void +SiS_Group2LCDSpecial(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT crt2crtc) +{ + USHORT tempcx; + const UCHAR atable[] = { + 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02, + 0xab,0x87,0xab,0x9e,0xe7,0x02,0x02 + }; + + if(!SiS_Pr->UseCustomMode) { + if( ( ( (HwInfo->jChipType == SIS_630) || + (HwInfo->jChipType == SIS_730) ) && + (HwInfo->jChipRevision > 2) ) && + (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) && + (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && + (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { + if(ModeNo == 0x13) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); + } else { + if((crt2crtc & 0x3F) == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); + } + } + } + + if(HwInfo->jChipType < SIS_315H) { + if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { + crt2crtc &= 0x1f; + tempcx = 0; + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + tempcx += 7; + } + } + tempcx += crt2crtc; + if(crt2crtc >= 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); + } - *CRT2Index = tempbx; - *ResIndex = tempal & 0x3F; + if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { + if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { + if(crt2crtc == 4) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); + } + } + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); + } + } + } } -#endif -#ifdef SIS300 /* For ECS A907. Highly preliminary. */ static void SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, @@ -7183,15 +6783,81 @@ if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750)) { if(SiS_Pr->SiS_TVMode & TVSetPALM) { SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b); } else { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x15); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14); /* 15 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1a); /* 1b */ } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b); } } } else { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x21); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x5a); + if((ModeNo == 0x38) || (ModeNo == 0x4a) || (ModeNo == 0x64) || + (ModeNo == 0x52) || (ModeNo == 0x58) || (ModeNo == 0x5c)) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 5a */ + } else { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1a); /* 21 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x53); /* 5a */ + } + } +} + +static void +SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo) +{ + USHORT temp; + + if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { + if(SiS_Pr->SiS_VGAVDE == 525) { + temp = 0xc3; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); + } else if(SiS_Pr->SiS_VGAVDE == 420) { + temp = 0x4d; + if(SiS_Pr->SiS_ModeType <= ModeVGA) { + temp++; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++; + } + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); + } + } + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { + if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03); + /* Not always for LV, see SetGrp2 */ + } + temp = 1; + if(ModeNo <= 0x13) temp = 3; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp); + } +#if 0 + /* 651+301C, for 1280x768 - do I really need that? */ + if((SiS_Pr->SiS_PanelXRes == 1280) && (SiS_Pr->SiS_PanelYRes == 768)) { + if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) { + if(((SiS_Pr->SiS_HDE == 640) && (SiS_Pr->SiS_VDE == 480)) || + ((SiS_Pr->SiS_HDE == 320) && (SiS_Pr->SiS_VDE == 240))) { + SiS_SetReg(SiS_Part2Port,0x01,0x2b); + SiS_SetReg(SiS_Part2Port,0x02,0x13); + SiS_SetReg(SiS_Part2Port,0x04,0xe5); + SiS_SetReg(SiS_Part2Port,0x05,0x08); + SiS_SetReg(SiS_Part2Port,0x06,0xe2); + SiS_SetReg(SiS_Part2Port,0x1c,0x21); + SiS_SetReg(SiS_Part2Port,0x1d,0x45); + SiS_SetReg(SiS_Part2Port,0x1f,0x0b); + SiS_SetReg(SiS_Part2Port,0x20,0x00); + SiS_SetReg(SiS_Part2Port,0x21,0xa9); + SiS_SetReg(SiS_Part2Port,0x23,0x0b); + SiS_SetReg(SiS_Part2Port,0x25,0x04); + } + } + } +#endif } } @@ -7200,36 +6866,26 @@ PSIS_HW_INFO HwInfo) { USHORT i, j, tempax, tempbx, tempcx, temp; - USHORT push1, push2, modeflag, crt2crtc; + USHORT push1, push2, modeflag, crt2crtc, bridgeoffset; ULONG longtemp, tempeax; const UCHAR *PhasePoint; const UCHAR *TimingPoint; #ifdef SIS315H USHORT resindex, CRT2Index; const SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL; -#endif -#ifdef SIS300 - const UCHAR atable[] = { - 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02, - 0xab,0x87,0xab,0x9e,0xe7,0x02,0x02 - }; -#endif -#ifdef SIS315H if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; #endif if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + crt2crtc = 0; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - crt2crtc = 0; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; } temp = 0; @@ -7238,26 +6894,25 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART) temp |= 0x02; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) temp |= 0x01; - /* Disable SVIDEO and CVBS signal */ - if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) && - (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) { - if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { - temp |= 0x0c; - } - } + if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) temp |= 0x10; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp); PhasePoint = SiS_Pr->SiS_PALPhase; TimingPoint = SiS_Pr->SiS_PALTiming; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { + TimingPoint = SiS_Pr->SiS_HiTVExtTiming; if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { TimingPoint = SiS_Pr->SiS_HiTVSt2Timing; if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { - if(modeflag & Charx8Dot) TimingPoint = SiS_Pr->SiS_HiTVSt1Timing; - else TimingPoint = SiS_Pr->SiS_HiTVTextTiming; + TimingPoint = SiS_Pr->SiS_HiTVSt1Timing; +#if 0 + if(!(modeflag & Charx8Dot)) TimingPoint = SiS_Pr->SiS_HiTVTextTiming; +#endif } - } else TimingPoint = SiS_Pr->SiS_HiTVExtTiming; + } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { @@ -7267,41 +6922,32 @@ PhasePoint = SiS_Pr->SiS_NTSCPhase; - } else { - - if(SiS_Pr->SiS_TVMode & TVSetPAL) { + } else if(SiS_Pr->SiS_TVMode & TVSetPAL) { - TimingPoint = SiS_Pr->SiS_PALTiming; - PhasePoint = SiS_Pr->SiS_PALPhase; + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_PALPhase2; + } - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_PALPhase2; - } + } else { - } else { + TimingPoint = SiS_Pr->SiS_NTSCTiming; + PhasePoint = SiS_Pr->SiS_NTSCPhase; + if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { + PhasePoint = SiS_Pr->SiS_PALPhase; + } - temp |= 0x10; - TimingPoint = SiS_Pr->SiS_NTSCTiming; - PhasePoint = SiS_Pr->SiS_NTSCPhase; + if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && + ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || + (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { + PhasePoint = SiS_Pr->SiS_NTSCPhase2; if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - PhasePoint = SiS_Pr->SiS_PALPhase; + PhasePoint = SiS_Pr->SiS_PALPhase2; } - - if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && - ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || - (SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) { - PhasePoint = SiS_Pr->SiS_NTSCPhase2; - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) { - PhasePoint = SiS_Pr->SiS_PALPhase2; - } - } - } } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x00,temp); if(SiS_Pr->SiS_TVMode & TVSetPALM) { PhasePoint = SiS_Pr->SiS_PALMPhase; @@ -7356,7 +7002,7 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempax = 950; else if(SiS_Pr->SiS_TVMode & TVSetPAL) tempax = 520; - else tempax = 440; + else tempax = 440; /* NTSC, YPbPr 525, 750 */ if( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) && (SiS_Pr->SiS_VDE <= tempax) ) || ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && @@ -7372,10 +7018,10 @@ temp = tempax + (USHORT)TimingPoint[1]; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); - if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) { if(SiS_Pr->SiS_TVMode & TVSetPAL) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x19); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x52); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b); /* 19 */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54); /* 52 */ } else { SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d); @@ -7388,10 +7034,8 @@ if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1; tempcx--; if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx--; - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,temp); - temp = (tempcx & 0xFF00) >> 8; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,(tempcx & 0xff)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f)); tempcx++; if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx++; @@ -7400,24 +7044,16 @@ push1 = tempcx; tempcx += 7; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - tempcx -= 4; - } - temp = (tempcx & 0x00FF) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,temp); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0)); - tempbx = TimingPoint[j] | ((TimingPoint[j+1]) << 8); + tempbx = TimingPoint[j] | (TimingPoint[j+1] << 8); tempbx += tempcx; - push2 = tempbx; - - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,tempbx); temp = ((tempbx & 0xFF00) >> 8) << 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,temp); - tempbx = push2; - tempbx += 8; if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { tempbx -= 4; @@ -7427,32 +7063,27 @@ SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,temp); j += 2; - tempcx += ((TimingPoint[j] | ((TimingPoint[j+1]) << 8))); + tempcx += (TimingPoint[j] | (TimingPoint[j+1] << 8)); temp = tempcx & 0x00FF; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,temp); temp = ((tempcx & 0xFF00) >> 8) << 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,temp); tempcx += 8; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) { - tempcx -= 4; - } - temp = (tempcx & 0x00FF) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,temp); + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0)); tempcx = push1; j += 2; tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8)); - temp = (tempcx & 0x00FF) << 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0)); tempcx -= 11; if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { tempcx = SiS_GetVGAHT2(SiS_Pr) - 1; } - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,tempcx); tempbx = SiS_Pr->SiS_VDE; if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746; @@ -7488,9 +7119,7 @@ if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) { - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { /* SetFlag?? */ - if(ModeNo == 0x03) temp++; - } + if(ModeNo == 0x03) temp++; } } } @@ -7499,20 +7128,19 @@ temp = (tempcx >> 8) & 0x0F; temp |= (((tempbx >> 8) << 6) & 0xC0); - if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750 | SetCRT2ToSCART))) { + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) { temp |= 0x10; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO)) temp |= 0x20; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO) temp |= 0x20; } SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp); - if((HwInfo->jChipType > SIS_315H) && (HwInfo->jChipType < SIS_661)) { - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { - if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ) { - SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60); - } - } + /* TEST qqqq */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { + for(i=0x01, j=0; i<=0x2D; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); + } + for(i=0x39; i<=0x45; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]); } } @@ -7524,21 +7152,27 @@ } } tempbx -= 3; - if(HwInfo->jChipType >= SIS_661) { - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { /* Why not 301B/LV? */ + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) { /* Why not 301B/LV? */ + if(HwInfo->jChipType >= SIS_661) { temp = 0; if(tempcx & 0x0400) temp |= 0x20; if(tempbx & 0x0400) temp |= 0x40; SiS_SetReg(SiS_Pr->SiS_Part4Port,0x10,temp); + } else { + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if((SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) || + (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) { + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60); + } + } } } tempbx &= 0x03ff; temp = ((tempbx & 0xFF00) >> 8) << 5; temp |= 0x18; SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp); - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,temp); - + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx); } tempbx = 0; @@ -7597,10 +7231,8 @@ tempbx = 0x0369; tempcx = 0x0061; } - temp = (tempbx & 0x00FF) ; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,temp); - temp = (tempcx & 0x00FF) ; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,tempbx); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,tempcx); temp = (tempcx & 0x0300) >> (8 - 2); temp |= ((tempbx >> 8) & 0x03); if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { @@ -7644,13 +7276,12 @@ tempbx = SiS_Pr->SiS_HDE; if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; tempbx--; /* RHACTE = HDE - 1 */ - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx); temp = (tempbx & 0xFF00) >> 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,temp); temp = 0x01; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { if(SiS_Pr->SiS_ModeType == ModeEGA) { if(SiS_Pr->SiS_VGAHDE >= 1024) { temp = 0x02; @@ -7665,14 +7296,12 @@ SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,temp); tempbx = SiS_Pr->SiS_VDE - 1; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,tempbx); temp = ((tempbx & 0xFF00) >> 8) & 0x07; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,temp); tempcx = SiS_Pr->SiS_VT - 1; - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,tempcx); temp = ((tempcx & 0xFF00) >> 8) << 5; @@ -7683,31 +7312,7 @@ } } - /* Must do special for Compaq1280; Acer1280 OK, Clevo1400 OK, COMPAL1400 OK */ - /* Compaq1280 panel loses sync if using CR37 sync info. */ - if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) { - if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) { - if(SiS_Pr->SiS_LCDInfo & LCDSync) { - temp |= ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); - } - } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)) { - temp |= 0x03; - } else { - temp |= (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) >> 6); - temp |= 0x08; - if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04; - } - } else { - if(SiS_Pr->SiS_LCDInfo & LCDSync) { - temp |= ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6); - } - } - } - - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1A,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1A,0x0f,temp); SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0); SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0); @@ -7715,154 +7320,13 @@ SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB); SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF); -#if 0 /* Use the 315/330 series code for now */ - if((HwInfo->jChipType >= SIS_661) && - (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && - (ROMAddr && SiS_Pr->SiS_UseROM)) { - - /* This is done for the LVDS bridges only, since - * the TMDS panels already work correctly with - * the old code. Besides, we only do that if - * we can get the data from the ROM, I am tired - * of carrying a lot of tables around. - */ - -#ifdef SIS315H /* ------------ 661/741/760 series --------- */ - UCHAR *myptr = NULL, myptr1 = NULL; - - myptr = (UCHAR *)GetLCDPtr661(SiS_Pr, HwInfo, 6, ModeNo, ModeIdIndex, RefreshRateTableIndex); - myptr1 = (UCHAR *)GetLCDStructPtr661(SiS_Pr, HwInfo); - - tempbx = (myptr[3] | (myptr[4] << 8)) & 0x0fff; - tempcx = SiS_Pr->PanelYRes; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - tempcx = SiS_Pr->SiS_VDE; - } - - tempcx += tempbx; - if(tempcx >= SiS_Pr->SiS_VT) tempcx -= SiS_Pr->SiS_VT; - - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempbx); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempcx); - - tempcx &= 0x07ff; - tempbx &= 0x07ff; - temp = (tempcx >> 8) << 3; - temp |= (tempbx >> 8); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); - - tempbx = (myptr[4] | (myptr[5] << 8)) >> 4; - tempcx = myptr1[6]; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempcx = myptr[7]; - - tempcx += tempbx; - if(tempcx >= SiS_Pr->SiS_VT) tempcx -= SiS_Pr->SiS_VT; - - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); - temp = tempcx & 0x000f; - temp |= ((tempbx & 0x0f00) >> 4); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); - - tempax = SiS_Pr->SiS_HT; - tempbx = (myptr[0] | (myptr[1] << 8)) & 0x0fff; - tempcx = SiS_Pr->PanelXRes; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempcx = SiS_Pr->SiS_HDE; - - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - tempax >>= 1; - tempbx >>= 1; - tempcx >>= 1; - } - if(SiS_Pr->SiS_VBType & VB_SIS302LV) tempbx++; - if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) tempbx++; - - tempcx += tempbx; - if(tempcx >= tempax) tempcx -= tempax; - - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,tempbx); - temp = ((tempbx & 0xff00) >> 8) << 4; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x20,temp); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempcx); - temp = tempcx >> 8; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x25,temp); - - tempax = SiS_Pr->SiS_HT; - tempbx = (myptr[1] | (myptr[2] << 8)) >> 4; - tempcx = myptr1[5]; - if(SiS_Pr->SiS_LCDInfo & LCDPass11) { - tempcx = myptr[6]; - } - if(SiS_IsDualLink(SiS_Pr, HwInfo)) { - tempax >>= 1; - tempbx >>= 1; - tempcx >>= 1; - } - if(SiS_Pr->SiS_VBType & VB_SIS302LV) tempbx++; - - tempcx += tempbx; - if(tempcx >= tempax) tempcx -= tempax; - - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1c,tempbx); - temp = (tempbx & 0x0f00) >> 4; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1d,0x0f,temp); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempcx); - - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(SiS_Pr->SiS_VGAVDE == 525) { - temp = 0xc3; - if(SiS_Pr->SiS_ModeType <= ModeVGA) { - temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2; - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); - } else if(SiS_Pr->SiS_VGAVDE == 420) { - temp = 0x4d; - if(SiS_Pr->SiS_ModeType <= ModeVGA) { - temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++; - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - } - } - -#endif - - } else -#endif - if((HwInfo->jChipType >= SIS_315H) && - (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && - ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) ) { - -#ifdef SIS315H /* ------------- 315/330 series ------------ */ - - SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &CRT2Index, &resindex, HwInfo); - +#ifdef SIS315H + if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, + &CRT2Index, &resindex, HwInfo)) { switch(CRT2Index) { - case Panel_1024x768 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; break; /* "Normal" */ - case Panel_1280x1024 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_1; break; - case Panel_1400x1050 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_1; break; - case Panel_1600x1200 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_1; break; - case Panel_1024x768 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2; break; /* Non-Expanding */ - case Panel_1280x1024 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_2; break; - case Panel_1400x1050 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_2; break; - case Panel_1600x1200 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_2; break; - case Panel_1024x768 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3; break; /* VESA Timing */ - case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break; - case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break; - case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break; - case 100: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_1; break; /* Custom */ - case 101: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_2; break; - case 102: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_3; break; - case 103: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_1; break; /* Custom */ - case 104: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_2; break; - case 105: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_3; break; - case 106: CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Asus1024x768_3; break; - default: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3; break; + case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1; break; + case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3; break; + default: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3; break; } SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]); @@ -7879,58 +7343,34 @@ SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]); SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]); - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(SiS_Pr->SiS_VGAVDE == 525) { - temp = 0xc3; - if(SiS_Pr->SiS_ModeType <= ModeVGA) { - temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2; - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3); - } else if(SiS_Pr->SiS_VGAVDE == 420) { - temp = 0x4d; - if(SiS_Pr->SiS_ModeType <= ModeVGA) { - temp++; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++; - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - } - } + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - /* See Sync above, 0x1a */ - temp = 1; - if(ModeNo <= 0x13) temp = 3; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp); - } - } + + } else { #endif - - } else { /* ------ 300 series and other bridges, other LCD resolutions ------ */ - - /* Using this on the 301B with an auto-expanding 1024 panel (CR37=1) makes - * the panel scale at modes < 1024 (no black bars); if the panel is non-expanding, - * the bridge scales all modes to 1024. - * !!! Malfunction at 640x480 and 640x400 when panel is auto-expanding - black screen !!! - */ - - tempcx = SiS_Pr->SiS_VT; - tempbx = SiS_Pr->PanelYRes; + + /* Checked for 1024x768, 1280x1024, 1400x1050, 1600x1200 */ + /* Clevo dual-link 1024x768 */ + /* Compaq 1280x1024 has HT 1696 sometimes (calculation OK, if given HT is correct) */ + /* Acer: OK, but uses different setting for VESA timing at 640/800/1024 and 640x400 */ if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - tempbx = SiS_Pr->SiS_VDE - 1; - tempcx--; - } - - tempax = 1; - if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) { - if(tempbx != SiS_Pr->SiS_VDE) { - tempax = tempbx; - if(tempax < SiS_Pr->SiS_VDE) { - tempax = 0; - tempcx = 0; + if((SiS_Pr->SiS_LCDInfo & LCDPass11) || (SiS_Pr->PanelYRes == SiS_Pr->SiS_VDE)) { + tempbx = SiS_Pr->SiS_VDE - 1; + tempcx = SiS_Pr->SiS_VT - 1; + } else { + tempbx = SiS_Pr->SiS_VDE + ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + tempcx = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2); + } + } else { + tempbx = SiS_Pr->PanelYRes; + tempcx = SiS_Pr->SiS_VT; + tempax = 1; + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempax = SiS_Pr->PanelYRes; + /* if(SiS_Pr->SiS_VGAVDE == 525) tempax += 0x3c; */ /* 651+301C */ + if(SiS_Pr->PanelYRes < SiS_Pr->SiS_VDE) { + tempax = tempcx = 0; } else { tempax -= SiS_Pr->SiS_VDE; } @@ -7946,23 +7386,46 @@ xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx); #endif - temp = tempcx & 0x00FF; /* RVEQ1EQ=lcdvdes */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,temp); - temp = tempbx & 0x00FF; /* RVEQ2EQ=lcdvdee */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx); /* lcdvdes */ + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx); /* lcdvdee */ temp = ((tempbx & 0xFF00) >> 8) << 3; temp |= ((tempcx & 0xFF00) >> 8); SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp); - tempbx = SiS_Pr->SiS_VT; /* push2; */ - tempax = SiS_Pr->SiS_VDE; /* push1; */ - tempcx = (tempbx - tempax) >> 4; - tempbx += tempax; - tempbx >>= 1; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx -= 10; + tempax = SiS_Pr->SiS_VDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + tempax = SiS_Pr->PanelYRes; + } + tempcx = (SiS_Pr->SiS_VT - tempax) >> 4; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + tempcx = (SiS_Pr->SiS_VT - tempax) / 10; + } + } + + tempbx = ((SiS_Pr->SiS_VT + SiS_Pr->SiS_VDE) >> 1) - 1; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) { + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { /* ? */ + tempax = SiS_Pr->SiS_VT - SiS_Pr->PanelYRes; + if(tempax % 4) { tempax >>= 2; tempax++; } + else { tempax >>= 2; } + tempbx -= (tempax - 1); + } else tempbx -= 10; + } + } + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { + tempbx++; + if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (crt2crtc == 6)) { + if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { + tempbx = 770; + tempcx = 3; + } + } + } - /* non-expanding: lcdvrs = tempbx = ((VT + VDE) / 2) - 10 */ + /* non-expanding: lcdvrs = ((VT + VDE) / 2) - 10 */ if(SiS_Pr->UseCustomMode) { tempbx = SiS_Pr->CVSyncStart; @@ -7972,8 +7435,7 @@ xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx); #endif - temp = tempbx & 0x00FF; /* RTVACTEE = lcdvrs */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx); /* lcdvrs */ temp = ((tempbx & 0xFF00) >> 8) << 4; tempbx += (tempcx + 1); @@ -7990,149 +7452,106 @@ SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp); - /* Code from 630/301B (I+II) BIOS */ - #ifdef SIS300 - if(!SiS_Pr->UseCustomMode) { - if( ( ( (HwInfo->jChipType == SIS_630) || - (HwInfo->jChipType == SIS_730) ) && - (HwInfo->jChipRevision > 2) ) && - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) && - (!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) && - (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) { - if(ModeNo == 0x13) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6); - } else { - if((crt2crtc & 0x3F) == 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2); - } - } - } - - if(HwInfo->jChipType < SIS_315H) { - if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) { - crt2crtc &= 0x1f; - tempcx = 0; - if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - tempcx += 7; - } - } - tempcx += crt2crtc; - if(crt2crtc >= 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff); - } + SiS_Group2LCDSpecial(SiS_Pr, HwInfo, ModeNo, crt2crtc); +#endif - if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) { - if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { - if(crt2crtc == 4) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28); - } - } - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]); - } + bridgeoffset = 7; + if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) bridgeoffset += 2; + if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) bridgeoffset++; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) bridgeoffset++; + + temp = 0; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp >>= 1; } } -#endif - - tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2; /* (HT - HDE) >> 2 */ - tempbx = SiS_Pr->SiS_HDE + 7; /* lcdhdee */ - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - tempbx += 2; + temp += bridgeoffset; + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp); /* lcdhdes[7:0] */ + temp = (temp >> 4) & 0xf0; + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0F,temp); /* lcdhdes [11:8] */ + + tempcx = SiS_Pr->SiS_HT; + tempax = tempbx = SiS_Pr->SiS_HDE; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) { + tempax = SiS_Pr->PanelXRes; + tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2); + } + } + if(SiS_IsDualLink(SiS_Pr, HwInfo)) { + tempcx >>= 1; + tempbx >>= 1; + tempax >>= 1; } - push1 = tempbx; #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx); #endif - temp = tempbx & 0x00FF; /* RHEQPLE = lcdhdee */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,temp); - temp = (tempbx & 0xFF00) >> 8; + tempbx += bridgeoffset; + + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx); /* lcdhdee */ + temp = (tempbx >> 8) & 0x0f; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,temp); - temp = 7; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - temp += 2; - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp); /* RHBLKE = lcdhdes[7:0] */ - SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x20,0x0F); /* lcdhdes [11:8] */ + tempcx = (tempcx - tempax) >> 2; tempbx += tempcx; push2 = tempbx; - if(SiS_Pr->UseCustomMode) { - tempbx = SiS_Pr->CHSyncStart + 7; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - tempbx += 2; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + if(SiS_Pr->SiS_HDE == 1280) tempbx = (tempbx & 0xff00) | 0x47; + } } } + if(SiS_Pr->UseCustomMode) { + tempbx = SiS_Pr->CHSyncStart; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx += bridgeoffset; + } + #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx); #endif - temp = tempbx & 0x00FF; /* RHBURSTS = lcdhrs */ - if(!SiS_Pr->UseCustomMode) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) { - if(SiS_Pr->SiS_HDE == 1280) temp = 0x47; - } - } - } - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx); /* lcdhrs */ temp = (tempbx & 0x0F00) >> 4; SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,temp); tempbx = push2; + tempcx <<= 1; + if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) { + if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) tempcx >>= 2; + } tempbx += tempcx; if(SiS_Pr->UseCustomMode) { - tempbx = SiS_Pr->CHSyncEnd + 7; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - tempbx += 2; - } + tempbx = SiS_Pr->CHSyncEnd; + if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; + tempbx += bridgeoffset; } #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx); #endif - temp = tempbx & 0x00FF; /* RHSYEXP2S = lcdhre */ - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,temp); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx); /* lcdhre */ - if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) { - if(SiS_Pr->SiS_VGAVDE == 525) { - if(SiS_Pr->SiS_ModeType <= ModeVGA) - temp=0xC6; - else - temp=0xC3; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xB3); - } else if(SiS_Pr->SiS_VGAVDE == 420) { - if(SiS_Pr->SiS_ModeType <= ModeVGA) - temp=0x4F; - else - temp=0x4D; - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp); - } - } + SiS_SetGroup2_Tail(SiS_Pr, ModeNo); #ifdef SIS300 - SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, - RefreshRateTableIndex, ModeNo); + SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, RefreshRateTableIndex, ModeNo); #endif - - } /* HwInfo */ +#ifdef SIS315H + } /* CRT2-LCD from table */ +#endif } /*********************************************/ @@ -8143,26 +7562,14 @@ SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo) { - USHORT modeflag, i; - const UCHAR *tempdi; + USHORT i; + const UCHAR *tempdi; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return; - if(ModeNo<=0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - } - #ifndef SIS_CP SiS_SetReg(SiS_Pr->SiS_Part3Port,0x00,0x00); -#endif - -#ifdef SIS_CP +#else SIS_CP_INIT301_CP #endif @@ -8185,9 +7592,6 @@ tempdi = SiS_Pr->SiS_HiTVGroup3Data; if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) { tempdi = SiS_Pr->SiS_HiTVGroup3Simu; - if(!(modeflag & Charx8Dot)) { - tempdi = SiS_Pr->SiS_HiTVGroup3Text; - } } } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) { if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) { @@ -8196,7 +7600,7 @@ } } if(tempdi) { - for(i=0; i<=0x3E; i++){ + for(i=0; i<=0x3E; i++) { SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]); } if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) { @@ -8206,17 +7610,92 @@ } } - if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) { #ifdef SIS_CP - SIS_CP_INIT301_CP2 + SIS_CP_INIT301_CP2 #endif - } } /*********************************************/ /* SET PART 4 REGISTER GROUP */ /*********************************************/ +#ifdef SIS315H +static void +SiS_ShiftXPos(SiS_Private *SiS_Pr, int shift) +{ + USHORT temp, temp1, temp2; + + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20); + temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0)); + temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f; + temp = (USHORT)((int)(temp) + shift); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f)); + temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43); + temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42); + temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0)); +} + +static void +SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, + USHORT ModeNo, USHORT ModeIdIndex) +{ + USHORT temp, temp1, resinfo = 0; + + if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return; + + if(ModeNo > 0x13) { + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; + } + + SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08); + temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a); + if(!(temp & 0x01)) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x3a,0xdf); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xfc); + if(HwInfo->jChipType < SIS_661) { + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8); + } + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb); + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) temp = 0x0000; + else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002; + else if(SiS_Pr->SiS_TVMode & TVSetHiVision) temp = 0x0400; + else temp = 0x0402; + if(HwInfo->jChipType >= SIS_661) { + temp1 = 0; + if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1); + if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff)); + } else { + temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03; + if(temp1 == 0x01) temp |= 0x01; + if(temp1 == 0x03) temp |= 0x04; /* ? why not 0x10? */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff)); + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8)); + + if(HwInfo->jChipType >= SIS_661) { /* ? */ + if(SiS_Pr->SiS_TVMode & TVAspect43) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) { + if(resinfo == SIS_RI_1024x768) { + SiS_ShiftXPos(SiS_Pr, 97); + } else { + SiS_ShiftXPos(SiS_Pr, 111); + } + } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) { + SiS_ShiftXPos(SiS_Pr, 136); + } + } + } + } +} +#endif + static void SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) @@ -8254,7 +7733,6 @@ SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp); } -/* Set 301 VGA2 registers */ static void SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo) @@ -8265,14 +7743,12 @@ if(ModeNo <= 0x13) { modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo; + } else if(SiS_Pr->UseCustomMode) { + modeflag = SiS_Pr->CModeFlag; + resinfo = 0; } else { - if(SiS_Pr->UseCustomMode) { - modeflag = SiS_Pr->CModeFlag; - resinfo = 0; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; - } + modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; + resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; } if(HwInfo->jChipType >= SIS_315H) { @@ -8298,7 +7774,7 @@ #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); } #endif @@ -8311,29 +7787,24 @@ SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,temp); tempbx = SiS_Pr->SiS_RVBHCMAX; - temp = tempbx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,temp); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,tempbx); - temp2 = (((tempbx & 0xFF00) >> 8) << 7) & 0x00ff; + temp2 = (tempbx >> 1) & 0x0080; tempcx = SiS_Pr->SiS_VGAHT - 1; - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,temp); + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,tempcx); - temp = (((tempcx & 0xFF00) >> 8) << 3) & 0x00ff; - temp2 |= temp; + temp2 |= (((tempcx & 0xFF00) >> 8) << 3) & 0x00ff; tempcx = SiS_Pr->SiS_VGAVT - 1; - if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5; - - temp = tempcx & 0x00FF; - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,temp); + if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5; + SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,tempcx); - temp = temp2 | ((tempcx & 0xFF00) >> 8); + temp = temp2 | (tempcx >> 8); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp); tempbx = SiS_Pr->SiS_VGAHDE; - if(modeflag & HalfDCLK) tempbx >>= 1; + if(modeflag & HalfDCLK) tempbx >>= 1; if(HwInfo->jChipType >= SIS_661) { if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1; } @@ -8370,7 +7841,7 @@ } if(SiS_Pr->SiS_VBType & VB_SIS301) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) + if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp |= 0x0A; } @@ -8420,14 +7891,11 @@ if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempax >>= 1; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { if(tempax > 800) tempax -= 800; - } else { + } else /* if(SiS_Pr->SiS_VBInfo & TvNoHiviNoYPbPr) */ { /* 651+301C */ if(tempax > 800) { tempbx = 8; - if(tempax == 1024) - tempax *= 25; - else - tempax *= 20; - + if(tempax == 1024) tempax *= 25; + else tempax *= 20; temp = tempax % 32; tempax /= 32; tempax--; @@ -8436,9 +7904,10 @@ } tempax--; temp = ((tempax & 0xFF00) >> 8) & 0x03; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* From 1.10.7w */ + if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) { /* From 1.10.7w */ if(ModeNo > 0x13) { /* From 1.10.7w */ if(resinfo == SIS_RI_1024x768) tempax = 0x1f; /* From 1.10.7w */ + /* ax normally 0x1e */ /* From 1.10.7w */ } /* From 1.10.7w */ } /* From 1.10.7w */ SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax & 0x00FF); @@ -8489,7 +7958,7 @@ #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); } #endif @@ -8504,7 +7973,6 @@ /* SET PART 5 REGISTER GROUP */ /*********************************************/ -/* Set 301 Palette address port registers */ static void SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex, PSIS_HW_INFO HwInfo) @@ -8514,7 +7982,7 @@ if(SiS_Pr->SiS_ModeType == ModeVGA) { if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) { - SiS_EnableCRT2(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20); SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); } } @@ -8532,11 +8000,8 @@ USHORT ResIndex,DisplayType; const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL; - if(ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } + if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; + else modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024) || @@ -8544,7 +8009,9 @@ return; if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, - &ResIndex, &DisplayType))) return; + &ResIndex, &DisplayType))) { + return; + } if(HwInfo->jChipType < SIS_315H) { if(SiS_Pr->SiS_SetFlag & SetDOSMode) return; @@ -8552,16 +8019,16 @@ switch(DisplayType) { case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1; break; - case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; - case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1; break; - case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H; break; - case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H; break; - case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H; break; - case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2; break; - case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2; break; - case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2; break; - case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H; break; - case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H; break; + case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H; break; + case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2; break; + case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H; break; + case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; + case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H; break; + case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2; break; + case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H; break; + case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1; break; + case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H; break; + case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2; break; case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H; break; case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1; break; case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H; break; @@ -8600,7 +8067,7 @@ default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1; break; } - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); /*unlock cr0-7 */ + SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); tempah = (LVDSCRT1Ptr + ResIndex)->CR[0]; SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,tempah); @@ -8635,12 +8102,6 @@ tempah <<= 5; if(modeflag & DoubleScanMode) tempah |= 0x080; SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah); - - /* 650/LVDS BIOS - doesn't make sense */ - if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - if(modeflag & HalfDCLK) - SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f); - } } /*********************************************/ @@ -8655,7 +8116,7 @@ USHORT clkbase, vclkindex=0; UCHAR sr2b, sr2c; - if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) || (SiS_Pr->SiS_IF_DEF_TRUMPION == 1)) { + if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) || (SiS_Pr->SiS_LCDInfo & LCDPass11)) { SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2); if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) { RefreshRateTableIndex--; @@ -8672,7 +8133,7 @@ sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C; if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x220] & 0x01) { sr2b = ROMAddr[0x227]; sr2c = ROMAddr[0x228]; @@ -8687,7 +8148,6 @@ } } - SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86); SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20); SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b); SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c); @@ -8712,9 +8172,9 @@ const SiS_CHTVRegDataStruct *CHTVRegData = NULL; if(ModeNo <= 0x13) - tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; + tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC; else - tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; + tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; TVType = 0; if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1; @@ -8732,16 +8192,16 @@ } } switch(TVType) { - case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; - case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; - case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; - case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; - case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; - case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; - case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; - case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; - case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; - default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break; + case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break; + case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL; break; + case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; + case 4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break; + case 5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break; + case 6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break; + case 7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break; + case 8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break; + default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL; break; } resindex = tempcl & 0x3F; @@ -9013,21 +8473,21 @@ /* Set up Power up/down timing */ if(HwInfo->jChipType == SIS_740) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740; else tableptr = table1024_740; - } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) { + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740; else tableptr = table1400_740; } else return; } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { tableptr = table1024_650; - } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) || - (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) { + } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) || + (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) || + (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) { tableptr = table1400_650; } else return; } @@ -9063,45 +8523,35 @@ int i; if(HwInfo->jChipType == SIS_740) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - tableptr = table1024_740; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tableptr = table1280_740; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - tableptr = table1400_740; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tableptr = table1600_740; - } else return; - } else { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { - tableptr = table1024_650; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { - tableptr = table1280_650; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { - tableptr = table1400_650; - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) { - tableptr = table1600_650; - } else return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_740; + else return; + } else { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tableptr = table1024_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_650; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_650; + else return; } tempbh = SiS_GetCH701x(SiS_Pr,0x74); if((tempbh == 0xf6) || (tempbh == 0xc7)) { tempbh = SiS_GetCH701x(SiS_Pr,0x73); if(tempbh == 0xc8) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) return; } else if(tempbh == 0xdb) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) return; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) return; } else if(tempbh == 0xde) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) return; } } - if(HwInfo->jChipType == SIS_740) { - tempbh = 0x0d; - } else { - tempbh = 0x0c; - } + if(HwInfo->jChipType == SIS_740) tempbh = 0x0d; + else tempbh = 0x0c; + for(i = 0; i < tempbh; i++) { SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]); } @@ -9488,13 +8938,12 @@ SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - /* Set up Panel Link for LVDS, 301BDH and 30xLV(for LCDA) */ + /* Set up Panel Link for LVDS and LCDA */ + SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) || ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) || ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) { SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); - } else { - SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0; } #ifdef LINUX_XF86 @@ -9521,11 +8970,16 @@ #endif SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo); +#ifdef SIS315H + SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); +#endif SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + /* For 301BDH (Panel link initialization): */ if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { + if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) { if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) { if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) { SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex, @@ -9540,28 +8994,25 @@ } else { - if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) { - if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) { - SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); - } + SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo); + + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); } - SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex,HwInfo); + SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo); if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) { -#ifdef SIS315H +#ifdef SIS315H SiS_SetCH701xForLCD(SiS_Pr,HwInfo); -#endif +#endif } } if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { - SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex, - RefreshRateTableIndex); + SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex); } } } @@ -9572,7 +9023,7 @@ if(HwInfo->jChipType < SIS_315H) { if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(SiS_Pr->SiS_UseOEM) { - if((SiS_Pr->SiS_UseROM) && ROMAddr && (SiS_Pr->SiS_UseOEM == -1)) { + if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) { if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) { SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex, RefreshRateTableIndex); @@ -9605,13 +9056,11 @@ if(SiS_Pr->SiS_SetFlag & LowModeTests) { if(HwInfo->jChipType < SIS_661) { SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex, HwInfo); - if(SiS_Pr->SiS_UseOEM) { - SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); - } + SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex); } else { SiS_OEM661Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex); } - SiS_CRT2AutoThreshold(SiS_Pr); + SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40); } } #endif @@ -9625,7 +9074,7 @@ if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* Disable LCD panel when using TV */ - SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x11,0x0C); + SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFF,0x0C); } else { /* Disable TV when using LCD */ SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8); @@ -9648,6 +9097,7 @@ SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { /* Switch on LCD backlight on SiS30xLV */ + SiS_DDC2Delay(SiS_Pr,0xff00); if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) { SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02); SiS_WaitVBRetrace(SiS_Pr,HwInfo); @@ -9663,12 +9113,81 @@ /* Switch off LCD backlight on SiS30xLV */ SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE); SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD); + SiS_DDC2Delay(SiS_Pr,0xe000); } /*********************************************/ /* DDC RELATED FUNCTIONS */ /*********************************************/ +static void +SiS_SetupDDCN(SiS_Private *SiS_Pr) +{ + SiS_Pr->SiS_DDC_NData = ~SiS_Pr->SiS_DDC_Data; + SiS_Pr->SiS_DDC_NClk = ~SiS_Pr->SiS_DDC_Clk; + if((SiS_Pr->SiS_DDC_Index == 0x11) && (SiS_Pr->SiS_SensibleSR11)) { + SiS_Pr->SiS_DDC_NData &= 0x0f; + SiS_Pr->SiS_DDC_NClk &= 0x0f; + } +} + +#ifdef SIS300 +static UCHAR * +SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr) +{ + int i, j, num; + USHORT tempah,temp; + UCHAR *mydataptr; + + for(i=0; i<20; i++) { /* Do 20 attempts to write */ + mydataptr = dataptr; + num = *mydataptr++; + if(!num) return mydataptr; + if(i) { + SiS_SetStop(SiS_Pr); + SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT*2); + } + if(SiS_SetStart(SiS_Pr)) continue; /* Set start condition */ + tempah = SiS_Pr->SiS_DDC_DeviceAddr; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write DAB (S0=0=write) */ + if(temp) continue; /* (ERROR: no ack) */ + tempah = *mydataptr++; + temp = SiS_WriteDDC2Data(SiS_Pr,tempah); /* Write register number */ + if(temp) continue; /* (ERROR: no ack) */ + for(j=0; jSiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + + SiS_SetSwitchDDC2(SiS_Pr); + + while(*dataptr) { + dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr); + if(!dataptr) return FALSE; + } +#ifdef TWDEBUG + xf86DrvMsg(0, X_INFO, "Trumpion block success\n"); +#endif + return TRUE; +} +#endif + /* The Chrontel 700x is connected to the 630/730 via * the 630/730's DDC/I2C port. * @@ -9704,18 +9223,32 @@ return FALSE; } +#ifdef SIS300 +/* Write Trumpion register */ +void +SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_SetChReg(SiS_Pr, tempbx, 0); +} +#endif + /* Write to Chrontel 700x */ /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */ void SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx) { - SiS_Pr->SiS_DDC_DataShift = 0x00; SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ if(!(SiS_Pr->SiS_ChrontelInit)) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); } if( (!(SiS_SetChReg(SiS_Pr, tempbx, 0x80))) && @@ -9723,6 +9256,7 @@ SiS_Pr->SiS_DDC_Index = 0x0a; /* Bit 7 = SC; Bit 6 = SD */ SiS_Pr->SiS_DDC_Data = 0x80; /* Bitmask in IndexReg for Data */ SiS_Pr->SiS_DDC_Clk = 0x40; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); SiS_SetChReg(SiS_Pr, tempbx, 0x80); } @@ -9736,19 +9270,18 @@ SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ - SiS_Pr->SiS_DDC_DataShift = 0x00; + SiS_SetupDDCN(SiS_Pr); SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB (Device Address Byte) */ - SiS_SetChReg(SiS_Pr, tempbx, 0); } void SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) { - if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) - SiS_SetCH700x(SiS_Pr,tempbx); - else - SiS_SetCH701x(SiS_Pr,tempbx); + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + SiS_SetCH700x(SiS_Pr,tempbx); + else + SiS_SetCH701x(SiS_Pr,tempbx); } static USHORT @@ -9780,6 +9313,21 @@ return 0xFFFF; } +#ifdef SIS300 +/* Read from Trumpion */ +USHORT +SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx) +{ + SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB */ + SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ + SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ + SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); + SiS_Pr->SiS_DDC_ReadAddr = tempbx; + return(SiS_GetChReg(SiS_Pr,0)); +} +#endif + /* Read from Chrontel 700x */ /* Parameter is [Register no (S7-S0)] */ USHORT @@ -9787,13 +9335,13 @@ { USHORT result; - SiS_Pr->SiS_DDC_DataShift = 0x00; SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ if(!(SiS_Pr->SiS_ChrontelInit)) { SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ SiS_Pr->SiS_DDC_Data = 0x02; /* Bitmask in IndexReg for Data */ SiS_Pr->SiS_DDC_Clk = 0x01; /* Bitmask in IndexReg for Clk */ + SiS_SetupDDCN(SiS_Pr); } SiS_Pr->SiS_DDC_ReadAddr = tempbx; @@ -9804,6 +9352,7 @@ SiS_Pr->SiS_DDC_Index = 0x0a; SiS_Pr->SiS_DDC_Data = 0x80; SiS_Pr->SiS_DDC_Clk = 0x40; + SiS_SetupDDCN(SiS_Pr); result = SiS_GetChReg(SiS_Pr,0x80); } @@ -9818,7 +9367,7 @@ SiS_Pr->SiS_DDC_Index = 0x11; /* Bit 0 = SC; Bit 1 = SD */ SiS_Pr->SiS_DDC_Data = 0x08; /* Bitmask in IndexReg for Data */ SiS_Pr->SiS_DDC_Clk = 0x04; /* Bitmask in IndexReg for Clk */ - SiS_Pr->SiS_DDC_DataShift = 0x00; + SiS_SetupDDCN(SiS_Pr); SiS_Pr->SiS_DDC_DeviceAddr = 0xEA; /* DAB */ SiS_Pr->SiS_DDC_ReadAddr = tempbx; @@ -9831,10 +9380,10 @@ USHORT SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx) { - if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) - return(SiS_GetCH700x(SiS_Pr, tempbx)); - else - return(SiS_GetCH701x(SiS_Pr, tempbx)); + if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) + return(SiS_GetCH700x(SiS_Pr, tempbx)); + else + return(SiS_GetCH701x(SiS_Pr, tempbx)); } /* Our own DDC functions */ @@ -9942,6 +9491,8 @@ SiS_Pr->SiS_DDC_Data = 0x02 << temp; SiS_Pr->SiS_DDC_Clk = 0x01 << temp; + SiS_SetupDDCN(SiS_Pr); + #ifdef TWDEBUG xf86DrvMsg(0, X_INFO, "DDC Port %x Index %x Shift %d\n", SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, temp); @@ -9986,11 +9537,15 @@ { SiS_SetSCLKLow(SiS_Pr); if(yesno) { - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data, SiS_Pr->SiS_DDC_Data); + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); } else { - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data, 0); + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0); } SiS_SetSCLKHigh(SiS_Pr); } @@ -10215,6 +9770,8 @@ for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE; SiS_Pr->CP_HaveCustomData = FALSE; SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0; + SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0; + SiS_Pr->CP_PreferredIndex = -1; if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0; if(pSiS->VBFlags & VB_30xBDH) return 0; @@ -10309,12 +9866,14 @@ SiS_Pr->CP_PreferredY = yres; switch(xres) { +#if 0 /* Treat as custom */ case 800: if(yres == 600) { paneltype = Panel_800x600; checkexpand = TRUE; } break; +#endif case 1024: if(yres == 768) { paneltype = Panel_1024x768; @@ -10352,9 +9911,11 @@ #if 0 /* Treat this as custom, as we have no valid timing data yet */ case 1600: if(pSiS->VGAEngine == SIS_315_VGA) { - if(yres == 1200) { - paneltype = Panel310_1600x1200; - checkexpand = TRUE; + if(pSiS->VBFlags & VB_301C) { + if(yres == 1200) { + paneltype = Panel310_1600x1200; + checkexpand = TRUE; + } } } break; @@ -10480,6 +10041,10 @@ if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres; if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; + if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) { + SiS_Pr->CP_PreferredIndex = i; + } + SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8); SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8); @@ -10560,28 +10125,20 @@ SiS_Pr->CP_MaxX = xres = buffer[0x76] | (buffer[0x77] << 8); SiS_Pr->CP_MaxY = yres = buffer[0x78] | (buffer[0x79] << 8); switch(xres) { +#if 0 case 800: if(yres == 600) { paneltype = Panel_800x600; checkexpand = TRUE; } break; +#endif case 1024: if(yres == 768) { paneltype = Panel_1024x768; checkexpand = TRUE; } break; - case 1152: - if(yres == 768) { - if(pSiS->VGAEngine == SIS_300_VGA) { - paneltype = Panel300_1152x768; - } else { - paneltype = Panel310_1152x768; - } - checkexpand = TRUE; - } - break; case 1280: if(yres == 960) { if(pSiS->VGAEngine == SIS_315_VGA) { @@ -10606,9 +10163,11 @@ #if 0 /* Treat this one as custom since we have no timing data yet */ case 1600: if(pSiS->VGAEngine == SIS_315_VGA) { - if(yres == 1200) { - paneltype = Panel310_1600x1200; - checkexpand = TRUE; + if(pSiS->VBFlags & VB_301C) { + if(yres == 1200) { + paneltype = Panel310_1600x1200; + checkexpand = TRUE; + } } } break; @@ -10710,6 +10269,10 @@ if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i]; + if((SiS_Pr->CP_MaxX == xres) && (SiS_Pr->CP_MaxY == yres)) { + SiS_Pr->CP_PreferredIndex = i; + } + SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE; SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE; SiS_Pr->CP_SyncValid[i] = TRUE; @@ -10764,10 +10327,11 @@ if(paneltype) { if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX; if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY; - cr37 &= 0xf1; - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x36,0xf0,paneltype); - SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xf1,cr37); SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08); + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x36,0xf0,paneltype); + cr37 &= 0xf1; + SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xf3,cr37); + SiS_Pr->PanelSelfDetected = TRUE; #ifdef TWDEBUG xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3, "CRT2: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37); @@ -10861,7 +10425,7 @@ } if(foundcrt) { - SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10); + SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x10); } return(0); } @@ -10903,11 +10467,15 @@ SiS_SetStart(SiS_Private *SiS_Pr) { if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data); /* SD->high */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high */ if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,0x00); /* SD->low = start condition */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low = start condition */ if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->low) */ return 0; } @@ -10918,11 +10486,15 @@ SiS_SetStop(SiS_Private *SiS_Pr) { if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF; /* (SC->low) */ - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,0x00); /* SD->low */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* SD->low */ if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* SC->high */ - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* SD->high = stop condition */ if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF; /* (SC->high) */ return 0; } @@ -10937,11 +10509,15 @@ for(i=0; i<8; i++) { SiS_SetSCLKLow(SiS_Pr); /* SC->low */ if(tempax & flag) { - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* Write bit (1) to SD */ } else { - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,0x00); /* Write bit (0) to SD */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + 0x00); /* Write bit (0) to SD */ } SiS_SetSCLKHigh(SiS_Pr); /* SC->high */ flag >>= 1; @@ -10959,8 +10535,10 @@ for(i=0; i<8; i++) { getdata <<= 1; SiS_SetSCLKLow(SiS_Pr); - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data); + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); SiS_SetSCLKHigh(SiS_Pr); temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01; @@ -10971,8 +10549,10 @@ USHORT SiS_SetSCLKLow(SiS_Private *SiS_Pr) { - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Clk,0x00); /* SetSCLKLow() */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + 0x00); /* SetSCLKLow() */ SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT); return 0; } @@ -10982,8 +10562,10 @@ { USHORT temp, watchdog=1000; - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Clk,SiS_Pr->SiS_DDC_Clk); /* SetSCLKHigh() */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NClk, + SiS_Pr->SiS_DDC_Clk); /* SetSCLKHigh() */ do { temp = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog); @@ -11005,10 +10587,12 @@ USHORT tempah; SiS_SetSCLKLow(SiS_Pr); /* (SC->low) */ - SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index, - ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data); /* (SD->high) */ + SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, + SiS_Pr->SiS_DDC_Index, + SiS_Pr->SiS_DDC_NData, + SiS_Pr->SiS_DDC_Data); /* (SD->high) */ SiS_SetSCLKHigh(SiS_Pr); /* SC->high = clock impulse for ack */ - tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);/* Read SD */ + tempah = SiS_GetReg(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index); /* Read SD */ SiS_SetSCLKLow(SiS_Pr); /* SC->low = end of clock impulse */ if(tempah & SiS_Pr->SiS_DDC_Data) return(1); /* Ack OK if bit = 0 */ else return(0); @@ -11028,13 +10612,13 @@ USHORT romptr; if(HwInfo->jChipType < SIS_330) { - romptr = ROMAddr[0x128] | (ROMAddr[0x129] << 8); + romptr = SISGETROMW(0x128); if(SiS_Pr->SiS_VBType & VB_SIS301B302B) - romptr = ROMAddr[0x12a] | (ROMAddr[0x12b] << 8); + romptr = SISGETROMW(0x12a); } else { - romptr = ROMAddr[0x1a8] | (ROMAddr[0x1a9] << 8); + romptr = SISGETROMW(0x1a8); if(SiS_Pr->SiS_VBType & VB_SIS301B302B) - romptr = ROMAddr[0x1aa] | (ROMAddr[0x1ab] << 8); + romptr = SISGETROMW(0x1aa); } return(romptr); } @@ -11046,13 +10630,13 @@ USHORT romptr; if(HwInfo->jChipType < SIS_330) { - romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8); + romptr = SISGETROMW(0x120); if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) - romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8); + romptr = SISGETROMW(0x122); } else { - romptr = ROMAddr[0x1a0] | (ROMAddr[0x1a1] << 8); + romptr = SISGETROMW(0x1a0); if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) - romptr = ROMAddr[0x1a2] | (ROMAddr[0x1a3] << 8); + romptr = SISGETROMW(0x1a2); } return(romptr); } @@ -11064,13 +10648,13 @@ USHORT romptr; if(HwInfo->jChipType < SIS_330) { - romptr = ROMAddr[0x114] | (ROMAddr[0x115] << 8); + romptr = SISGETROMW(0x114); if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) - romptr = ROMAddr[0x11a] | (ROMAddr[0x11b] << 8); + romptr = SISGETROMW(0x11a); } else { - romptr = ROMAddr[0x194] | (ROMAddr[0x195] << 8); + romptr = SISGETROMW(0x194); if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) - romptr = ROMAddr[0x19a] | (ROMAddr[0x19b] << 8); + romptr = SISGETROMW(0x19a); } return(romptr); } @@ -11092,9 +10676,9 @@ } } - index = SiS_Pr->SiS_LCDResInfo & 0x0F; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) index -= 5; - else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) index -= 6; + index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F; + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) index -= 5; + else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6; index--; index *= 3; if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; @@ -11107,12 +10691,9 @@ { USHORT index; - index = SiS_Pr->SiS_LCDResInfo & 0x0F; - index--; - index *= 3; - if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; + index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3; + if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2; else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++; - return index; } @@ -11122,8 +10703,10 @@ USHORT index; index = 0; - if(SiS_Pr->SiS_TVMode & TVSetPAL) index++; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index++; /* HiVision uses PAL */ + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 1; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) index = 2; + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) index = 0; index <<= 1; @@ -11136,7 +10719,7 @@ } static ULONG -GetOEMTVPtr661_2(SiS_Private *SiS_Pr) +GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme) { USHORT index = 0, temp = 0; @@ -11153,7 +10736,7 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) { - index += 8; + index += addme; temp++; } temp += 0x0100; @@ -11161,16 +10744,37 @@ return(ULONG)(index | (temp << 16)); } +static ULONG +GetOEMTVPtr661_2_OLD(SiS_Private *SiS_Pr) +{ + return(GetOEMTVPtr661_2_GEN(SiS_Pr, 8)); +} + +#if 0 +static ULONG +GetOEMTVPtr661_2_NEW(SiS_Private *SiS_Pr) +{ + return(GetOEMTVPtr661_2_GEN(SiS_Pr, 6)); +} +#endif + static int GetOEMTVPtr661(SiS_Private *SiS_Pr) { int index = 0; - if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 2; - if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 4; - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6; - if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8; - if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10; + if(SiS_Pr->SiS_TVMode & TVSetPAL) index = 2; + if(SiS_Pr->SiS_ROMNew) { + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 10; + } else { + if(SiS_Pr->SiS_TVMode & TVSetHiVision) index = 4; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8; + if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10; + } if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) index++; @@ -11184,15 +10788,21 @@ USHORT delay=0,index,myindex,temp,romptr=0; BOOLEAN dochiptest = TRUE; + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf); + } else { + SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x35,0x7f); + } + /* Find delay (from ROM, internal tables, PCI subsystem) */ if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) { /* ------------ VGA */ - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { romptr = GetRAMDACromptr(SiS_Pr, HwInfo); - if(!romptr) return; - delay = ROMAddr[romptr]; - } else { + } + if(romptr) delay = ROMAddr[romptr]; + else { delay = 0x04; if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { if(IS_SIS650) { @@ -11204,8 +10814,7 @@ } else { delay = 0x0c; } - } - if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { + } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { delay = 0x00; } } @@ -11214,13 +10823,39 @@ BOOLEAN gotitfrompci = FALSE; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return; + /* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */ + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + if(SiS_Pr->PDC != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((SiS_Pr->PDC >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((SiS_Pr->PDC & 0x01) << 7)); + return; + } + } else { + if(SiS_Pr->PDCA != -1) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDCA << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((SiS_Pr->PDCA & 0x01) << 6)); + return; + } + } - /* Could we detect a PDC for LCD? If yes, use it */ + /* Custom Panel? */ - if(SiS_Pr->PDC) { + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) { if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDC & 0x0f) << 4)); + delay = 0x00; + if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) { + delay = 0x20; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay); + } else { + delay = 0x0c; + if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x03; + else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(IS_SIS740) delay = 0x01; + else delay = 0x03; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,delay); } return; } @@ -11233,7 +10868,7 @@ switch(SiS_Pr->SiS_CustomT) { case CUT_COMPAQ1280: case CUT_COMPAQ12802: - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { gotitfrompci = TRUE; dochiptest = FALSE; delay = 0x03; @@ -11241,15 +10876,13 @@ break; case CUT_CLEVO1400: case CUT_CLEVO14002: - /* if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { */ - gotitfrompci = TRUE; - dochiptest = FALSE; - delay = 0x02; - /* } */ + gotitfrompci = TRUE; + dochiptest = FALSE; + delay = 0x02; break; case CUT_CLEVO1024: case CUT_CLEVO10242: - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { gotitfrompci = TRUE; dochiptest = FALSE; delay = 0x33; @@ -11270,21 +10903,16 @@ if(SiS_IsNotM650orLater(SiS_Pr, HwInfo)) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { -#if 0 /* Always use the second pointer on 650; some BIOSes */ + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ /* still carry old 301 data at the first location */ - romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8); - if(SiS_Pr->SiS_VBType & VB_SIS302LV) -#endif - romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8); + /* romptr = SISGETROMW(0x120); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x122); if(!romptr) return; delay = ROMAddr[(romptr + index)]; } else { - delay = SiS310_LCDDelayCompensation_650301B[myindex]; -#if 0 - if(SiS_Pr->SiS_VBType & VB_SIS302LV) - delay = SiS310_LCDDelayCompensation_650301B[myindex]; -#endif + delay = SiS310_LCDDelayCompensation_650301LV[myindex]; } } else { @@ -11295,34 +10923,34 @@ } - } else if((ROMAddr) && SiS_Pr->SiS_UseROM && - (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) { + } else if(SiS_Pr->SiS_UseROM && + (!(SiS_Pr->SiS_ROMNew)) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x768) && + (SiS_Pr->SiS_LCDResInfo != Panel_1280x960)) { + /* Data for 1280x1024 wrong in 301B BIOS */ romptr = GetLCDromptr(SiS_Pr, HwInfo); if(!romptr) return; delay = ROMAddr[(romptr + index)]; } else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) { - if(IS_SIS650) { - delay = SiS310_LCDDelayCompensation_LVDS650[myindex]; - } else { - delay = SiS310_LCDDelayCompensation_LVDS740[myindex]; - } + if(IS_SIS740) delay = 0x03; + else delay = 0x00; } else { delay = SiS310_LCDDelayCompensation_301[myindex]; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { -#if 0 /* This data is (like the one in the BIOS) wrong. */ - if(IS_SIS550650740660) { - delay = SiS310_LCDDelayCompensation_650301B[myindex]; - } else { -#endif - delay = SiS310_LCDDelayCompensation_3xx301B[myindex]; -#if 0 - } -#endif + if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) { + if(IS_SIS740) delay = 0x01; + else delay = SiS310_LCDDelayCompensation_650301LV[myindex]; + } else if(SiS_Pr->SiS_VBType & VB_SIS301C) { + if(IS_SIS740) delay = 0x01; /* ? */ + else delay = 0x03; + } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) { + if(IS_SIS740) delay = 0x01; + else delay = SiS310_LCDDelayCompensation_3xx301B[myindex]; } } @@ -11342,23 +10970,19 @@ if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { -#if 0 /* Always use the second pointer on 650; some BIOSes */ + if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { + /* Always use the second pointer on 650; some BIOSes */ /* still carry old 301 data at the first location */ - romptr = ROMAddr[0x114] | (ROMAddr[0x115] << 8); - if(SiS_Pr->SiS_VBType & VB_SIS302LV) -#endif - romptr = ROMAddr[0x11a] | (ROMAddr[0x11b] << 8); + /* romptr = SISGETROMW(0x114); */ + /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */ + romptr = SISGETROMW(0x11a); if(!romptr) return; delay = ROMAddr[romptr + index]; } else { delay = SiS310_TVDelayCompensation_301B[index]; -#if 0 - if(SiS_Pr->SiS_VBType & VB_SIS302LV) - delay = SiS310_TVDelayCompensation_301B[index]; -#endif + } } else { @@ -11384,7 +11008,7 @@ } } - } else if((ROMAddr) && SiS_Pr->SiS_UseROM) { + } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) { romptr = GetTVromptr(SiS_Pr, HwInfo); if(!romptr) return; @@ -11400,14 +11024,16 @@ if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { if(IS_SIS740) { delay = SiS310_TVDelayCompensation_740301B[index]; + /* LV: use 301 data? BIOS bug? */ } else { delay = SiS310_TVDelayCompensation_301B[index]; + if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x02; } } } - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) { /* LCDA */ + if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) { delay &= 0x0f; dochiptest = FALSE; } @@ -11470,18 +11096,21 @@ index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex; temp = GetTVPtrIndex(SiS_Pr); - temp >>= 1; /* 0: NTSC, 1: PAL, 2: HiTV */ + temp >>= 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ temp1 = temp; - if(ROMAddr && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { if(HwInfo->jChipType >= SIS_661) { - romptr = ROMAddr[0x260] | (ROMAddr[0x261] << 8); - temp1 = GetOEMTVPtr661(SiS_Pr); + temp1 = GetOEMTVPtr661(SiS_Pr); temp1 >>= 1; + romptr = SISGETROMW(0x260); + if(HwInfo->jChipType >= SIS_760) { + romptr = SISGETROMW(0x360); + } } else if(HwInfo->jChipType >= SIS_330) { - romptr = ROMAddr[0x192] | (ROMAddr[0x193] << 8); + romptr = SISGETROMW(0x192); } else { - romptr = ROMAddr[0x112] | (ROMAddr[0x113] << 8); + romptr = SISGETROMW(0x112); } } @@ -11503,24 +11132,25 @@ UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT index,temp,temp1,romptr=0; - temp = GetTVPtrIndex(SiS_Pr); - temp >>= 1; /* 0: NTSC, 1: PAL, 2: HiTV */ - temp1 = temp; + temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ - if(ModeNo<=0x13) + if(ModeNo <= 0x13) index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex; else index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex; - if(ROMAddr && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) { if(HwInfo->jChipType >= SIS_661) { - romptr = ROMAddr[0x26c] | (ROMAddr[0x26d] << 8); + romptr = SISGETROMW(0x26c); + if(HwInfo->jChipType >= SIS_760) { + romptr = SISGETROMW(0x36c); + } temp1 = GetOEMTVPtr661(SiS_Pr); temp1 >>= 1; } else if(HwInfo->jChipType >= SIS_330) { - romptr = ROMAddr[0x1a4] | (ROMAddr[0x1a5] << 8); + romptr = SISGETROMW(0x1a4); } else { - romptr = ROMAddr[0x124] | (ROMAddr[0x125] << 8); + romptr = SISGETROMW(0x124); } } @@ -11538,62 +11168,15 @@ SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo,USHORT ModeIdIndex) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; - USHORT index, myindex, oldindex,temp, i, j, flag1 = 0, flag2 = 0, romptr = 0; - ULONG lindex; + USHORT index, temp, i, j; - if(ModeNo<=0x13) { - index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; + if(ModeNo <= 0x13) { + index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex; } else { - index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; - } - - oldindex = index; - - if((HwInfo->jChipType >= SIS_661) && ROMAddr && SiS_Pr->SiS_UseROM) { - if(ModeNo > 0x13) { - index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndexROM661; - } - lindex = GetOEMTVPtr661_2(SiS_Pr); - if(lindex & 0x00ff0000) flag1 = 1; - if(lindex & 0xff000000) flag2 = 1; - lindex &= 0xffff; - - /* NTSC-J: Use PAL filters */ - if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) lindex = 1; - - romptr = ROMAddr[0x268] | (ROMAddr[0x269] << 8); - if(flag1) myindex = index * 7; - else myindex = index << 2; - - if(romptr) { - romptr += (lindex << 1); - romptr = (ROMAddr[romptr] | (ROMAddr[romptr+1] << 8)) + myindex; - if(romptr) { - if((!flag1) && (flag2)) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x35,0x00); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x36,0x00); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,0x00); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,ROMAddr[romptr++]); - } else { - for(i=0x35; i<=0x38; i++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr++]); - } - } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - for(j=0, i=0x48; i<=0x4a; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr++]); - } - } - return; - } - } + index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex; } - index = oldindex; - - temp = GetTVPtrIndex(SiS_Pr); - temp >>= 1; /* 0: NTSC, 1: PAL, 2: HiTV */ + temp = GetTVPtrIndex(SiS_Pr) >> 1; /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */ if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) temp = 1; /* NTSC-J uses PAL */ else if(SiS_Pr->SiS_TVMode & TVSetPALM) temp = 3; /* PAL-M */ @@ -11627,21 +11210,11 @@ /* NTSC-J data not in BIOS, and already set in SetGroup2 */ if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return; - if(HwInfo->jChipType >= SIS_661) { - lindex = GetOEMTVPtr661_2(SiS_Pr) & 0xffff; + if((HwInfo->jChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) { + lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff; lindex <<= 2; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - romptr = ROMAddr[0x264] | (ROMAddr[0x265] << 8); - } - if(romptr) { - romptr += lindex; - for(j=0, i=0x31; i<=0x34; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); - } - } else { - for(j=0, i=0x31; i<=0x34; i++, j++) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]); - } + for(j=0, i=0x31; i<=0x34; i++, j++) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]); } return; } @@ -11659,20 +11232,20 @@ /* 0: NTSC Graphics, 1: NTSC Text, 2: PAL Graphics, * 3: PAL Text, 4: HiTV Graphics 5: HiTV Text */ - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8); + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x116); if(HwInfo->jChipType >= SIS_330) { - romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8); + romptr = SISGETROMW(0x196); } if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - romptr = ROMAddr[0x11c] | (ROMAddr[0x11d] << 8); + romptr = SISGETROMW(0x11c); if(HwInfo->jChipType >= SIS_330) { - romptr = ROMAddr[0x19c] | (ROMAddr[0x19d] << 8); + romptr = SISGETROMW(0x19c); } if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) { - romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8); + romptr = SISGETROMW(0x116); if(HwInfo->jChipType >= SIS_330) { - romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8); + romptr = SISGETROMW(0x196); } } } @@ -11695,19 +11268,19 @@ } } - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - if((!(SiS_Pr->SiS_TVMode & TVSetPAL)) && (ModeNo > 0x13)) { + if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision))) { + if((!(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetYPbPr525p | TVSetYPbPr750p))) && (ModeNo > 0x13)) { if((resinfo == SIS_RI_640x480) || (resinfo == SIS_RI_800x600)) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x21); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0xf0); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xf5); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7f); - } else if (resinfo == SIS_RI_1024x768) { - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x1e); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0x8b); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xfb); - SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x21); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0xf0); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xf5); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7f); + } else if(resinfo == SIS_RI_1024x768) { + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x31,0x1e); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x32,0x8b); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x33,0xfb); + SiS_SetReg(SiS_Pr->SiS_Part2Port,0x34,0x7b); } } } @@ -11722,12 +11295,12 @@ if(SiS_Pr->UseCustomMode) return; if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) { - SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { - SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - } + SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + if(SiS_Pr->SiS_VBType & VB_SIS301) { + SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); + } } } @@ -11735,65 +11308,104 @@ SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex, USHORT RTI) { - UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT delay = 0, romptr = 0, index; - UCHAR *myptr = NULL; - UCHAR temp; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC))) return; - delay = SiS_Pr->SiS_RefIndex[RTI].Ext_PDC; + /* 1. New ROM: VGA2 and LCD/LCDA-Pass1:1 */ + + if(SiS_Pr->SiS_ROMNew) { + if((SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) || + ((SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) && + (SiS_Pr->SiS_LCDInfo & LCDPass11))) { + index = 25; + if(SiS_Pr->UseCustomMode) { + index = SiS_Pr->CSRClock; + } else if(ModeNo > 0x13) { + index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI,HwInfo); + index = SiS_Pr->SiS_VCLKData[index].CLOCK; + } + if(index < 25) index = 25; + index = ((index / 25) - 1) << 1; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) index++; + romptr = SISGETROMW(0x104); /* 0x4ae */ + delay = ROMAddr[romptr + index]; + if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } + return; + } + } + + /* 2. Old ROM: VGA2 and LCD/LCDA-Pass 1:1 */ - delay &= 0xf0; - delay >>= 4; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) delay <<= 12; /* BIOS: 8, wrong */ + if(SiS_Pr->UseCustomMode) delay = 0x04; + else if(ModeNo <= 0x13) delay = 0x04; + else delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4); + delay |= (delay << 8); if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { + + /* 3. TV */ + index = GetOEMTVPtr661(SiS_Pr); - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - romptr = ROMAddr[0x25c] | (ROMAddr[0x25d] << 8); - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - romptr = ROMAddr[0x25e] | (ROMAddr[0x25f] << 8); - } - } - if(romptr) myptr = &ROMAddr[romptr]; - if(!myptr) { - myptr = (UCHAR *)SiS_TVDelay661_301; - if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) { - myptr = (UCHAR *)SiS_TVDelay661_301B; - } + if(SiS_Pr->SiS_ROMNew) { + romptr = SISGETROMW(0x106); /* 0x4ba */ + delay = ROMAddr[romptr + index]; + } else { + delay = 0x04; } - delay = myptr[index]; - if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) delay >>= 4; /* Should test dual edge */ + } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(SiS_Pr->PDC) { - delay = SiS_Pr->PDC & 0x0f; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - delay |= (delay << 12); - } - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) { - delay = 0x4444; /* TEST THIS */ - } else if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { - myptr = GetLCDStructPtr661(SiS_Pr, HwInfo); - if(myptr) delay = myptr[4]; - else delay = 0x44; - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - delay |= (delay << 8); + + /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */ + + if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) && + ((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) ) { + + /* For LV, the BIOS must know about the correct value */ + delay = ROMAddr[romptr + 0x0d]; /* LCD */ + delay |= (ROMAddr[romptr + 0x0c] << 8); /* LCDA */ + + } else { + + /* TMDS: Set our own, since BIOS has no idea - TODO: Find out about values */ + if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { + if((SiS_Pr->PanelXRes <= 1024) && (SiS_Pr->PanelYRes <= 768)) { + delay = 0x0404; + } else if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) { + delay = 0x0404; + } else if((SiS_Pr->PanelXRes <= 1400) && (SiS_Pr->PanelYRes <= 1050)) { + delay = 0x1004; + } else + delay = 0x0000; } + } - } - temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2d); - if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToRAMDAC)) { - temp &= 0xf0; - temp |= (delay & 0x000f); + /* Override by detected or user-set values */ + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->PDC != -1)) { + delay = SiS_Pr->PDC & 0x1f; + } + if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) && (SiS_Pr->PDCA != -1)) { + delay = (SiS_Pr->PDCA & 0x1f) << 8; + } } + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - temp &= 0x0f; - temp |= ((delay & 0xf000) >> 8); + delay >>= 8; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6)); + } else { + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f)); + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7)); } - SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,temp); } static void @@ -11802,38 +11414,50 @@ USHORT infoflag; UCHAR temp; - infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag; - if(ModeNo <= 0x13) { - infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2); - } - infoflag &= 0xc0; if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { + + if(ModeNo <= 0x13) { + infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2); + } else if(SiS_Pr->UseCustomMode) { + infoflag = SiS_Pr->CInfoFlag; + } else { + infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag; + } + infoflag &= 0xc0; + temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37); - if(temp & 0x20) infoflag = temp; + if(SiS_Pr->SiS_LCDInfo & LCDPass11) { + temp &= 0x3f; + temp |= infoflag; + } else { + if(temp & 0x20) infoflag = temp; + } if(temp & 0x01) infoflag |= 0x01; - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { - temp = 0x0c; - if(infoflag & 0x01) temp ^= 0x14; /* BIOS: 18, wrong */ - temp |= (infoflag >> 6); - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp); - } - if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - temp = 0; - if(infoflag & 0x01) temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp); - temp = 0x30; - if(infoflag & 0x01) temp = 0x20; - infoflag &= 0xc0; - temp |= infoflag; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp); + + if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) { + temp = 0x0c; + if(infoflag & 0x01) temp ^= 0x14; /* BIOS: 18, wrong */ + temp |= (infoflag >> 6); + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp); + } else { + temp = 0; + if(infoflag & 0x01) temp |= 0x80; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp); + temp = 0x30; + if(infoflag & 0x01) temp = 0x20; + infoflag &= 0xc0; + temp |= infoflag; + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp); + } + } } static void SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo) { - UCHAR *myptr; + UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; + USHORT romptr, temp1, temp2; if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { if(SiS_Pr->LVDSHL != -1) { @@ -11841,16 +11465,22 @@ } } - myptr = GetLCDStructPtr661(SiS_Pr, HwInfo); - if(myptr) { - if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { - if(SiS_Pr->LVDSHL == -1) { - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xE0,myptr[1] & 0x1f); - } else { - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xE3,myptr[1] & 0x1c); - } + if(SiS_Pr->SiS_ROMNew) { + + if((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) { + if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) { + temp1 = (ROMAddr[romptr] & 0x03) | 0x0c; + temp2 = 0xfc; + if(SiS_Pr->LVDSHL != -1) { + temp1 &= 0xfc; + temp2 = 0xf3; + } + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,temp2,temp1); + } + temp1 = (ROMAddr[romptr + 1] & 0x80) >> 1; + SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0xbf,temp1); } - SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0x3f,myptr[2] & 0xc0); + } } @@ -11871,7 +11501,7 @@ SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); - if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) { + if(SiS_Pr->SiS_VBType & VB_SIS301) { SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex); } } @@ -11900,7 +11530,7 @@ } } - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; if(SiS_Pr->UseCustomMode) return; switch(SiS_Pr->SiS_CustomT) { @@ -11930,7 +11560,7 @@ } if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { /* Maybe all panels? */ if(SiS_Pr->LVDSHL == -1) { SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); @@ -11941,7 +11571,7 @@ if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) { if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(SiS_Pr->LVDSHL == -1) { /* Maybe all panels? */ SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); @@ -11961,15 +11591,15 @@ } if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { #ifdef SET_EMI if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) { SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00); - SiS_SetReg(SiS_Pr->SiS_Part4Port,0x30,0x00); + SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c); SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10); } #endif - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) { + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) { if(SiS_Pr->LVDSHL == -1) { /* Maybe ACER only? */ SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01); @@ -11977,9 +11607,9 @@ } tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4; if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) { - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1f,0x76); - } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + } else if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(tempch == 0x03) { SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02); SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25); @@ -12060,7 +11690,7 @@ tempbh >>= 4; tempbl = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x04); tempbx = (tempbh << 8) | tempbl; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) { if(SiS_Pr->SiS_SetFlag & LCDVESATiming) { tempbx = 770; @@ -12151,19 +11781,16 @@ tempbx = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f) - 2; if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) { + if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) { if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3; } - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(ROMAddr[0x235] & 0x80) { tempbx = SiS_Pr->SiS_LCDTypeInfo; if(Flag) { - romptr = ROMAddr[0x255] | (ROMAddr[0x256] << 8); - if(romptr) { - tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; - } else { - tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo]; - } + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo]; if(tempbx == 0xFF) return 0xFFFF; } tempbx <<= 1; @@ -12174,13 +11801,10 @@ } else { if(Flag) { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { - romptr = ROMAddr[0x255] | (ROMAddr[0x256] << 8); - if(romptr) { - tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; - } else { - tempbx = 0xff; - } + if(SiS_Pr->SiS_UseROM) { + romptr = SISGETROMW(0x255); + if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo]; + else tempbx = 0xff; } else { tempbx = customtable630[SiS_Pr->SiS_LCDTypeInfo]; } @@ -12204,12 +11828,12 @@ UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT index,temp,romptr=0; - if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return; + if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x237] & 0x01)) return; if(!(ROMAddr[0x237] & 0x02)) return; - romptr = ROMAddr[0x24b] | (ROMAddr[0x24c] << 8); + romptr = SISGETROMW(0x24b); } /* The Panel Compensation Delay should be set according to tables @@ -12219,7 +11843,7 @@ * Thus we don't set this if the user select a custom pdc or if * we otherwise detected a valid pdc. */ - if(SiS_Pr->PDC) return; + if(SiS_Pr->PDC != -1) return; temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 0); @@ -12231,7 +11855,7 @@ if(HwInfo->jChipType != SIS_300) { if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += index; temp = ROMAddr[romptr]; } else { @@ -12242,21 +11866,21 @@ } } } else { - if((ROMAddr) && SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) { + if(SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) { if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += index; temp = ROMAddr[romptr]; } else { temp = SiS300_OEMLCDDelay5[temp][index]; } } else { - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { romptr = ROMAddr[0x249] | (ROMAddr[0x24a] << 8); if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += index; temp = ROMAddr[romptr]; } else { @@ -12279,7 +11903,7 @@ UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT index,temp; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if((SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x237] & 0x01)) return; if(!(ROMAddr[0x237] & 0x04)) return; /* No rom pointer in BIOS header! */ @@ -12329,10 +11953,10 @@ UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT index,temp,romptr=0; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; if(!(ROMAddr[0x238] & 0x02)) return; - romptr = ROMAddr[0x241] | (ROMAddr[0x242] << 8); + romptr = SISGETROMW(0x241); } temp = GetOEMTVPtr(SiS_Pr); @@ -12341,7 +11965,7 @@ if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += index; temp = ROMAddr[romptr]; } else { @@ -12352,7 +11976,7 @@ } } temp &= 0x3c; - SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); /* index 0A D[6:4] */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp); } static void @@ -12362,10 +11986,10 @@ UCHAR *ROMAddr = HwInfo->pjVirtualRomBase; USHORT index,temp,romptr=0; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; if(!(ROMAddr[0x238] & 0x04)) return; - romptr = ROMAddr[0x243] | (ROMAddr[0x244] << 8); + romptr = SISGETROMW(0x243); } temp = GetOEMTVPtr(SiS_Pr); @@ -12374,14 +11998,14 @@ if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += index; temp = ROMAddr[romptr]; } else { temp = SiS300_OEMTVFlicker[temp][index]; } temp &= 0x70; - SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp); /* index 0A D[6:4] */ + SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp); } static void @@ -12395,10 +12019,10 @@ if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetNTSCJ | TVSetPALM | TVSetPALN)) return; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; if(!(ROMAddr[0x238] & 0x08)) return; - romptr = ROMAddr[0x245] | (ROMAddr[0x246] << 8); + romptr = SISGETROMW(0x245); } temp = GetOEMTVPtr(SiS_Pr); @@ -12412,7 +12036,7 @@ } else { if(romptr) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += (index * 4); for(i=0x31, j=0; i<=0x34; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); @@ -12434,10 +12058,10 @@ if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return; - if((ROMAddr) && SiS_Pr->SiS_UseROM) { + if(SiS_Pr->SiS_UseROM) { if(!(ROMAddr[0x238] & 0x01)) return; if(!(ROMAddr[0x238] & 0x10)) return; - romptr = ROMAddr[0x247] | (ROMAddr[0x248] << 8); + romptr = SISGETROMW(0x247); } temp = GetOEMTVPtr(SiS_Pr); @@ -12458,7 +12082,7 @@ } else { if((romptr) && (!(SiS_Pr->SiS_TVMode & (TVSetPALM|TVSetPALN)))) { romptr += (temp * 2); - romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8); + romptr = SISGETROMW(romptr); romptr += (index * 4); for(i=0x35, j=0; i<=0x38; i++, j++) { SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]); diff -urN linux-2.4.25/drivers/video/sis/init301.h linux-2.4.26/drivers/video/sis/init301.h --- linux-2.4.25/drivers/video/sis/init301.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/init301.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -91,29 +88,41 @@ 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b, 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17, 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02, - 0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40, - 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53, + 0x03,0x0a,0x65,0x8d /*0x9d*/,0x08,0x92,0x8f,0x40, + 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50 /*0x53*/, 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00 }, { 0x1d,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c, 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, - 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13, + 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4c /*0x4f*/,0x13, 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8, - 0x51,0x5e,0x60,0x49,0x7d,0x92,0x0f,0x40, + 0x51,0x5e,0x60,0x57 /*0x49*/,0x7b /*0x7d*/,0x92,0x0f,0x40, 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4b, 0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00 }, { +#if 1 0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c, 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, - 0xed,0x50,0x70,0x9f,0x16,0x59,0x2b,0x13, + 0xed,0x50,0x70,0x9f,0x16,0x59,0x21 /*0x2b*/,0x13, 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0, - 0x4b,0x4b,0x6f,0x2f,0x63,0x92,0x0f,0x40, + 0x4b,0x4b,0x65 /*0x6f*/,0x2f,0x63,0x92,0x0f,0x40, 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27, 0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00 +#endif +#if 0 + 0x2a,0x14,0xe8,0x09,0x09,0xed,0x0c,0x0c, /* TEST (0.93) - BAD */ + 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a, + 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f, + 0xed,0x50,0x70,0x9e,0x16,0x57,0x6c,0x13, + 0x27,0x0b,0x27,0xfb,0x30,0x27,0x15,0xb0, + 0x3b,0xdb,0x61,0x24,0x78,0x92,0x0f,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x14,0x6f, + 0x00,0x52,0xbb,0x00,0xd5,0xf7,0xa2,0x00 +#endif } }; @@ -139,7 +148,7 @@ 0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01 }; -/* 301C / 302ELV (?) extended Part2 TV registers */ +/* 301C / 302ELV extended Part2 TV registers */ static const UCHAR SiS_Part2CLVX_1[] = { 0x00,0x00, @@ -208,7 +217,7 @@ 0x00,0x04, 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, - 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x1D,0x7C,0x0D,0x18,0x7F, + 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x1D /* 0x7D? */ ,0x7C,0x0D,0x18,0x7F, 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02, 0xFF,0xFF, }; @@ -217,19 +226,80 @@ #ifdef SIS315H /* 661 et al LCD data structure */ static const UCHAR SiS_LCDStruct661[] = { - /* 1600x1200 */ - 0x0B,0xEA,0x81,0x10,0x00,0xC0,0x03,0x21,0x5A,0x23,0x5A,0x23,0x02, - 0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10, - /* 1400x1050 */ - 0x09,0xEA,0x81,0x80,0xA3,0x70,0x03,0x19,0xD2,0x2A,0xF8,0x2F,0x02, - 0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10, - /* 1280x1024 */ - 0x03,0xEA,0x81,0x40,0xA1,0x70,0x03,0x19,0xD2,0x2A,0xF8,0x2F,0x02, - 0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10, /* 1024x768 */ - 0x02,0xEA,0x80,0x00,0x11,0x88,0x06,0x0B,0xF5,0x6C,0x35,0x62,0x02, - 0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x28,0x10, - 0xFF, +/* type|CR37| HDE | VDE | HT | VT | hss | hse */ + 0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88, + 0x00,0x02,0x00,0x06,0x00,0x41,0x5A,0x64,0x37,0x6E,0x05,0x6E,0x04, + /* | vss | vse |clck| clock |CRT2DataP|CRT2DataP|idx */ + /* VESA non-VESA noscale */ + /* 1280x1024 */ + 0x03,0xE0,0x00,0x05,0x00,0x04,0x98,0x06,0x2A,0x04,0x30,0x00,0x70, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x5F,0x6F,0xDB,0x6F,0x08, + /* 1400x1050 */ + 0x09,0x20,0x78,0x05,0x1A,0x04,0x98,0x06,0x2A,0x04,0x18,0x00,0x38, + 0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x35,0x70,0x00,0x00,0x09, + /* 1600x1200 */ + 0x0B,0xE0,0x40,0x06,0xB0,0x04,0x70,0x08,0xE2,0x04,0x40,0x00,0xC0, + 0x00,0x01,0x00,0x03,0x00,0xA2,0x70,0x24,0x07,0x71,0x00,0x00,0x0B, + /* 1280x768 */ + 0x0A,0xC0,0x00,0x05,0x00,0x03,0x80,0x05,0x26,0x03,0x10,0x00,0x40, + 0x00,0x03,0x00,0x06,0x00,0x44,0x63,0x46,0xEB,0x6E,0xA5,0x6E,0x06, + /* 1280x720 */ + 0x0E,0xE0,0x00,0x05,0xD0,0x02,0x40,0x05,0x26,0x03,0x10,0x00,0x02, + 0x00,0x01,0x00,0x06,0x00,0x41,0x5A,0x64,0x69,0x6E,0x00,0x00,0x05, +#if 0 /* 0.92: */ + 0x0E,0xE0,0x00,0x05,0xD0,0x02,0x72,0x06,0xEE,0x02,0x2A,0x00,0x3F, + 0x00,0x01,0x00,0x06,0x00,0x41,0x00,0x00,0xA7,0x6A,0x00,0x00,0x05, +#endif + /* 1280x800 */ + 0x0C,0xE0,0x00,0x05,0x20,0x03,0x80,0x05,0x30,0x03,0x15,0x00,0x18, + 0x00,0x04,0x00,0x03,0x00,0x45,0x9C,0x62,0x31,0x6F,0x00,0x00,0x07, + /* 1680x1050 */ + 0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C, + 0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x99,0x70,0x00,0x00,0x0A, /* 0.93: 0x0A=0x06 - WRONG? */ + /* 1280x768 (not in 0.93) */ + 0x0A,0xC0,0x00,0x05,0x00,0x03,0x80,0x06,0x1E,0x03,0x40,0x00,0x80, + 0x00,0x03,0x00,0x07,0x00,0x4F,0x00,0x00,0x6F,0x6B,0x00,0x00,0x06 +}; +#endif + +#ifdef SIS300 +static UCHAR SiS300_TrumpionData[7][80] = { + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xBC,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x09,0x04,0x04,0x05, + 0x04,0x0C,0x09,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5A,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x27,0x00,0x80,0x02, + 0x20,0x03,0x07,0x00,0x5E,0x01,0x0D,0x02,0x60,0x0C,0x30,0x11,0x00,0x00,0x04,0x23, + 0x00,0x00,0x03,0x80,0x03,0x28,0x06,0x08,0x40,0x11,0x00,0x11,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x90,0x01,0xFF,0x0F,0xF4,0x19,0x01,0x00,0x05,0x01,0x00,0x04,0x05, + 0x04,0x0C,0x02,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEC,0x57,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xD9,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x59,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02, + 0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23, + 0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05, + 0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02, + 0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05, + 0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03, + 0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D, + 0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D, + 0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B, + 0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }, + { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04, + 0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23, + 0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23, + 0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01, + 0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 } }; #endif @@ -271,6 +341,12 @@ void SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); #endif /* 315 */ +#ifdef SIS300 +void SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); +USHORT SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx); +static BOOLEAN SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr); +#endif + USHORT SiS_ReadDDC1Bit(SiS_Private *SiS_Pr); void SiS_SetSwitchDDC2(SiS_Private *SiS_Pr); @@ -338,5 +414,6 @@ extern void SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO,USHORT ModeNo, USHORT ModeIdIndex); +extern void SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex); #endif diff -urN linux-2.4.25/drivers/video/sis/initdef.h linux-2.4.26/drivers/video/sis/initdef.h --- linux-2.4.25/drivers/video/sis/initdef.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/initdef.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -72,6 +69,8 @@ #define IS_SIS650740660 (IS_SIS650 || IS_SIS740 || IS_SIS661741660760) #define IS_SIS550650740660 (IS_SIS550 || IS_SIS650740660) +#define SISGETROMW(x) (ROMAddr[(x)] | (ROMAddr[(x)+1] << 8)) + /* SiS_VBType */ #define VB_SIS301 0x0001 #define VB_SIS301B 0x0002 @@ -102,7 +101,7 @@ #define SetNotSimuMode 0x0400 #define SetNotSimuTVMode SetNotSimuMode #define SetDispDevSwitch 0x0800 -#define SetCRT2ToYPbPr525750 0x0800 /* 661 */ +#define SetCRT2ToYPbPr525750 0x0800 #define LoadDACFlag 0x1000 #define DisableCRT2Display 0x2000 #define DriverMode 0x4000 @@ -145,7 +144,7 @@ #define SupportCHTV 0x0800 #define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ #define SupportHiVision 0x0010 -#define SupportYPbPr 0x1000 /* TODO */ +#define SupportYPbPr750p 0x1000 #define SupportLCD 0x0020 #define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ #define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ @@ -174,20 +173,23 @@ #define TVSetPALM 0x0004 #define TVSetPALN 0x0008 #define TVSetCHOverScan 0x0010 -#define TVSetYPbPr525i 0x0020 -#define TVSetYPbPr525p 0x0040 -#define TVSetYPbPr750p 0x0080 -#define TVSetHiVision 0x0100 -#define TVSetTVSimuMode 0x0800 -#define TVRPLLDIV2XO 0x1000 -#define TVSetNTSC1024 0x2000 - -/* YPbPr flag (>=315, <661; YPbPr not supported yet) */ -#define YPbPr750 0x0001 /* 750p (must be a single bit, checked logially) */ -#define YPbPr525 0x0002 /* 525p (must be a single bit, checked logially) */ -#define YPbPrHiVision 0x0003 /* HiVision */ -#define YPbPrModeMask (YPbPr750 | YPbPr525 | YPbPrHiVision) -#define YPbPrSetSVideo 0x0004 /* (sets SVIDEO flag) */ +#define TVSetYPbPr525i 0x0020 /* new 0x10 */ +#define TVSetYPbPr525p 0x0040 /* new 0x20 */ +#define TVSetYPbPr750p 0x0080 /* new 0x40 */ +#define TVSetHiVision 0x0100 /* new 0x80; = 1080i, software-wise identical */ +#define TVSetTVSimuMode 0x0200 /* new 0x200, prev. 0x800 */ +#define TVRPLLDIV2XO 0x0400 /* prev 0x1000 */ +#define TVSetNTSC1024 0x0800 /* new 0x100, prev. 0x2000 */ +#define TVAspect43 0x2000 +#define TVAspect169 0x4000 +#define TVAspect43LB 0x8000 + +/* YPbPr flag (>=315, <661; converted to TVMode) */ +#define YPbPr525p 0x0001 +#define YPbPr750p 0x0002 +#define YPbPr525i 0x0004 +#define YPbPrHiVision 0x0008 +#define YPbPrModeMask (YPbPr750p | YPbPr525p | YPbPr525i | YPbPrHiVision) /* SysFlags (to identify special versions) */ #define SF_Is651 0x0001 @@ -198,6 +200,7 @@ #define SF_IsM661 0x0020 #define SF_IsM741 0x0040 #define SF_IsM760 0x0080 +#define SF_760UMA 0x8000 /* CR32 (Newer 630, and 315 series) @@ -223,11 +226,11 @@ [2] 1 = PALM (if D0 = 1) [3] 1 = PALN (if D0 = 1) [4] 1 = Overscan (Chrontel only) - [7:5] (only if D2 in CR38 is set; not supported yet) + [7:5] (only if D2 in CR38 is set) 000 525i 001 525p 010 750p - 011 HiVision (Should be 1080i, but...) + 011 1080i (or HiVision on 301, 301B) These bits are being translated to TVMode flag. @@ -269,7 +272,7 @@ #define LCDRGB18Bit 0x0001 #define LCDNonExpanding 0x0010 #define LCDSync 0x0020 -#define LCDPass11 0x0100 +#define LCDPass11 0x0100 /* 0: center screen, 1: Pass 1:1 data */ #define LCDDualLink 0x0200 #define DontExpandLCD LCDNonExpanding @@ -281,13 +284,13 @@ /* CR38 (315 series) */ #define EnableDualEdge 0x01 #define SetToLCDA 0x02 /* LCD channel A (301C/302B/30x(E)LV and 650+LVDS only) */ -#define EnableSiSYPbPr 0x04 /* YPbPr on SiS bridge (not used; also on 661) */ #define EnableCHScart 0x04 /* Scart on Ch7019 (unofficial definition - TW) */ #define EnableCHYPbPr 0x08 /* YPbPr on Ch7019 (480i HDTV); only on 650/Ch7019 systems */ -#define EnableYPbPr750 0x08 /* Enable 750P YPbPr mode (30xLV/301C only) (not supported) */ -#define EnableYPbPr525 0x10 /* Enable 525P YPbPr mode (30xLV/301C only) (not supported) */ -#define EnableYPbPrHiVision 0x18 /* Enable HiVision (not supported) */ -#define EnableYPbPrsetSVideo 0x20 /* Enable YPbPr and set SVideo */ +#define EnableSiSYPbPr 0x08 /* Enable YPbPr mode (30xLV/301C only) */ +#define EnableYPbPr525i 0x00 /* Enable 525i YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr525p 0x10 /* Enable 525p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr750p 0x20 /* Enable 750p YPbPr mode (30xLV/301C only) (mask 0x30) */ +#define EnableYPbPr1080i 0x30 /* Enable 1080i YPbPr mode (30xLV/301C only) (mask 0x30) */ #define EnablePALM 0x40 /* 1 = Set PALM */ #define EnablePALN 0x80 /* 1 = Set PALN */ #define EnableNTSCJ EnablePALM /* Not BIOS */ @@ -305,10 +308,10 @@ #define EnablePALMN 0x40 /* Romflag: 1 = Allow PALM/PALN */ /* CR39 (650 only) */ -#define LCDPass1_1 0x01 /* LVDS only; set by driver to pass 1:1 data to LVDS output */ +#define LCDPass1_1 0x01 /* 0: center screen, 1: pass 1:1 data output */ #define Enable302LV_DualLink 0x04 /* 302LV only; enable dual link */ -/* CR39 (661 and later; not yet implemented) +/* CR39 (661 and later) D[1:0] YPbPr Aspect Ratio 00 4:3 letterbox 01 4:3 @@ -316,6 +319,11 @@ 11 4:3 */ +/* CR3B (651+301C) + D[1:0] YPbPr Aspect Ratio + ? +*/ + /* CR79 (315/330 series only; not 661 and later) [3-0] Notify driver 0001 Mode Switch event (set by BIOS) @@ -343,7 +351,7 @@ #define Panel300_1024x600 0x06 #define Panel300_1152x768 0x07 #define Panel300_1280x768 0x0a -#define Panel300_320x480 0x0e /* fstn - TW: This is fake, can be any */ +#define Panel300_320x480 0x0e /* fstn - This is fake, can be any */ #define Panel300_Custom 0x0f #define Panel300_Barco1366 0x10 @@ -363,8 +371,24 @@ #define Panel310_320x480 0x0e /* fstn - TW: This is fake, can be any */ #define Panel310_Custom 0x0f +#define Panel661_800x600 0x01 +#define Panel661_1024x768 0x02 +#define Panel661_1280x1024 0x03 +#define Panel661_640x480 0x04 +#define Panel661_1024x600 0x05 +#define Panel661_1152x864 0x06 +#define Panel661_1280x960 0x07 +#define Panel661_1152x768 0x08 +#define Panel661_1400x1050 0x09 +#define Panel661_1280x768 0x0a +#define Panel661_1600x1200 0x0b +#define Panel661_1280x800 0x0c +#define Panel661_1680x1050 0x0d +#define Panel661_1280x720 0x0e +#define Panel661_Custom 0x0f + #define Panel_800x600 0x01 /* Unified values */ -#define Panel_1024x768 0x02 +#define Panel_1024x768 0x02 /* MUST match BIOS values from 0-e */ #define Panel_1280x1024 0x03 #define Panel_640x480 0x04 #define Panel_1024x600 0x05 @@ -372,16 +396,19 @@ #define Panel_1280x960 0x07 #define Panel_1152x768 0x08 /* LVDS only */ #define Panel_1400x1050 0x09 -#define Panel_1280x768 0x0a /* LVDS only */ +#define Panel_1280x768 0x0a /* 30xB/C and LVDS only (BIOS: all) */ #define Panel_1600x1200 0x0b -#define Panel_640x480_2 0x0c -#define Panel_640x480_3 0x0d -#define Panel_320x480 0x0e /* fstn - TW: This is fake, can be any */ -#define Panel_Custom 0x0f -#define Panel_Barco1366 0x10 -#define Panel_848x480 0x11 -#define Panel_1280x800 0x12 /* 661etc: 0x0c */ -#define Panel_1680x1050 0x13 /* 661etc: 0x0d */ +#define Panel_1280x800 0x0c /* 661etc */ +#define Panel_1680x1050 0x0d /* 661etc */ +#define Panel_1280x720 0x0e /* 661etc */ +#define Panel_Custom 0x0f /* MUST BE 0x0f (for DVI DDC detection */ +#define Panel_320x480 0x10 /* SiS 550 fstn - TW: This is fake, can be any */ +#define Panel_Barco1366 0x11 +#define Panel_848x480 0x12 +#define Panel_640x480_2 0x13 /* SiS 550 */ +#define Panel_640x480_3 0x14 /* SiS 550 */ +#define Panel_1280x768_2 0x15 /* 30xLV */ +#define Panel_1280x768_3 0x16 /* 30xLV */ /* Index in ModeResInfo table */ #define SIS_RI_320x200 0 @@ -413,6 +440,8 @@ #define SIS_RI_1152x768 26 #define SIS_RI_768x576 27 #define SIS_RI_1360x1024 28 +#define SIS_RI_1680x1050 29 +#define SIS_RI_1280x800 30 /* CR5F */ #define IsM650 0x80 @@ -440,14 +469,22 @@ #define VCLK108_3_300 0x42 /* Index in VCLKData table (300) */ #define VCLK100_300 0x43 /* Index in VCLKData table (300) */ #define VCLK34_300 0x3d /* Index in VCLKData table (300) */ +#define VCLK_CUSTOM_300 0x46 #define VCLK65_315 0x0b /* Index in (VB)VCLKData table (315) */ #define VCLK108_2_315 0x19 /* Index in (VB)VCLKData table (315) */ #define VCLK81_315 0x5b /* Index in (VB)VCLKData table (315) */ -#define VCLK162_315 0x21 /* Index in (VB)VCLKData table (315) */ +#define VCLK162_315 0x5e /* Index in (VB)VCLKData table (315) */ #define VCLK108_3_315 0x45 /* Index in VBVCLKData table (315) */ #define VCLK100_315 0x46 /* Index in VBVCLKData table (315) */ -#define VCLK34_315 0x55 /* Index in VBVCLKData table (315) */ +#define VCLK34_315 0x55 #define VCLK68_315 0x0d +#define VCLK69_315 0x5c /* Index in VBVCLKData table (315) */ +#define VCLK121_315 0x5d /* Index in VBVCLKData table (315) */ +#define VCLK_1280x720 0x5f +#define VCLK_1280x768_2 0x60 +#define VCLK_1280x768_3 0x61 +#define VCLK_CUSTOM_315 0x62 +#define VCLK_1280x720_2 0x63 #define TVCLKBASE_300 0x21 /* Indices on TV clocks in VCLKData table (300) */ #define TVCLKBASE_315 0x3a /* Indices on TV clocks in (VB)VCLKData table (315) */ @@ -457,7 +494,7 @@ #define HiTVVCLK 0x03 /* Index relative to TVCLKBASE */ #define HiTVSimuVCLK 0x04 /* Index relative to TVCLKBASE */ #define HiTVTextVCLK 0x05 /* Index relative to TVCLKBASE */ -#define YPbPr750pVCLK 0x0f /* NOT relative to TVCLKBASE ! */ +#define YPbPr750pVCLK 0x25 /* Index relative to TVCLKBASE; was 0x0f NOT relative */ /* ------------------------------ */ diff -urN linux-2.4.25/drivers/video/sis/oem300.h linux-2.4.26/drivers/video/sis/oem300.h --- linux-2.4.25/drivers/video/sis/oem300.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/oem300.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, diff -urN linux-2.4.25/drivers/video/sis/oem310.h linux-2.4.26/drivers/video/sis/oem310.h --- linux-2.4.25/drivers/video/sis/oem310.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/oem310.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -72,7 +69,7 @@ }; /* This is contained in 650+301B BIOSes, but it is wrong - so we don't use it */ -static const UCHAR SiS310_LCDDelayCompensation_650301B[] = /* 30xB,LV */ +static const UCHAR SiS310_LCDDelayCompensation_650301LV[] = /* 650 + 30xLV */ { 0x01,0x01,0x01, /* 800x600 */ 0x01,0x01,0x01, /* 1024x768 */ @@ -91,65 +88,7 @@ 0x02,0x02,0x02 }; -/* This data is correct, so we use it instead of the table above */ -static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB,LV */ -{ - 0x01,0x01,0x01, /* 800x600 */ - 0x0C,0x0C,0x0C, /* 1024x768 */ - 0x0C,0x0C,0x0C, /* 1280x1024 */ - 0x08,0x08,0x08, /* 640x480 */ - 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ - 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ - 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ - 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02, - 0x02,0x02,0x02 -}; - -static const UCHAR SiS310_LCDDelayCompensation_LVDS650[] = /* LVDS */ -{ - 0x00,0x00,0x00, /* 800x600 */ - 0x00,0x00,0x00, /* 1024x768 */ - 0x00,0x00,0x00, /* 1280x1024 */ - 0x00,0x00,0x00, /* 640x480 (unknown) */ - 0x00,0x00,0x00, /* 1024x600 (unknown) */ - 0x00,0x00,0x00, /* 1152x864 (unknown) */ - 0x00,0x00,0x00, /* 1280x960 (guessed) */ - 0x00,0x00,0x00, /* 1152x768 (unknown) */ - 0x00,0x00,0x00, /* 1400x1050 */ - 0x00,0x00,0x00, /* 1280x768 (guessed) */ - 0x00,0x00,0x00, /* 1600x1200 */ - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00 -}; - -static const UCHAR SiS310_LCDDelayCompensation_LVDS740[] = /* LVDS */ -{ - 0x03,0x03,0x03, /* 800x600 */ - 0x03,0x03,0x03, /* 1024x768 */ - 0x03,0x03,0x03, /* 1280x1024 */ - 0x03,0x03,0x03, /* 640x480 (unknown) */ - 0x03,0x03,0x03, /* 1024x600 (unknown) */ - 0x03,0x03,0x03, /* 1152x864 (unknown) */ - 0x03,0x03,0x03, /* 1280x960 (guessed) */ - 0x03,0x03,0x03, /* 1152x768 (unknown) */ - 0x03,0x03,0x03, /* 1400x1050 */ - 0x03,0x03,0x03, /* 1280x768 (guessed) */ - 0x03,0x03,0x03, /* 1600x1200 */ - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00, - 0x00,0x00,0x00 -}; - -static const UCHAR SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ +static const UCHAR SiS310_LCDDelayCompensation_651301LV[] = /* M650/651 301LV */ { 0x33,0x33,0x33, /* 800x600 (guessed) - new: PanelType, not PanelRes ! */ 0x33,0x33,0x33, /* 1024x768 */ @@ -168,7 +107,7 @@ 0x33,0x33,0x33 }; -static const UCHAR SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ +static const UCHAR SiS310_LCDDelayCompensation_651302LV[] = /* M650/651 302LV */ { 0x33,0x33,0x33, /* 800x600 (guessed) */ 0x33,0x33,0x33, /* 1024x768 */ @@ -187,6 +126,25 @@ 0x33,0x33,0x33 }; +static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] = /* 30xB,LV */ +{ + 0x01,0x01,0x01, /* 800x600 */ + 0x0C,0x0C,0x0C, /* 1024x768 */ + 0x0C,0x0C,0x0C, /* 1280x1024 */ + 0x08,0x08,0x08, /* 640x480 */ + 0x0C,0x0C,0x0C, /* 1024x600 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x864 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x960 (guessed) */ + 0x0C,0x0C,0x0C, /* 1152x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1400x1050 (guessed) */ + 0x0C,0x0C,0x0C, /* 1280x768 (guessed) */ + 0x0C,0x0C,0x0C, /* 1600x1200 (guessed) */ + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02, + 0x02,0x02,0x02 +}; + static const UCHAR SiS310_TVDelayCompensation_301[] = /* 301 */ { 0x02,0x02, /* NTSC Enhanced, Standard */ @@ -208,13 +166,6 @@ 0x05,0x05 }; -static const UCHAR SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ -{ - 0x0a,0x0a, - 0x0a,0x0a, - 0x0a,0x0a -}; - static const UCHAR SiS310_TVDelayCompensation_651301LV[] = /* M650, 651, 301LV */ { 0x33,0x33, @@ -249,6 +200,13 @@ 0x44,0x44 }; +static const UCHAR SiS310_TVDelayCompensation_LVDS[] = /* LVDS */ +{ + 0x0a,0x0a, + 0x0a,0x0a, + 0x0a,0x0a +}; + static const UCHAR SiS310_TVAntiFlick1[6][2] = { {0x4,0x0}, @@ -451,141 +409,6 @@ { 1, 1,1696,1066,1696,1066} }; -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_1[] = -{ - {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x35,0x1B,0xA0,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x45,0x1C,0x20,0x3F,0xFF,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}}, - {{0x49,0x1C,0x40,0x7F,0xFF,0xAD,0x23,0x0A,0x07,0xF3,0x8A,0x12}}, - {{0x4C,0x1C,0x18,0x2F,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}} -}; - -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_2[] = -{ - {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}}, - {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}}, - {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}}, - {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}}, - {{0x33,0x13,0x01,0x0D,0xFD,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}}, - {{0x3F,0x1B,0x3D,0x49,0x39,0x54,0x23,0xC0,0x27,0x66,0x30,0x42}}, - {{0x33,0x1B,0x91,0x9D,0x8D,0x8C,0x23,0xF8,0x27,0x9E,0x68,0x42}}, - {{0x43,0x24,0x11,0x1D,0x0D,0xCC,0x23,0x38,0x37,0xDE,0xA8,0x42}}, - {{0x43,0x24,0x21,0x29,0x19,0xEA,0x23,0x0A,0x07,0x32,0xC6,0x42}} -}; - -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_3[] = -{ - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}, - {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}} -}; - -/* LCDA CRT2 data is std */ - -static const SiS_LVDSDesStruct Compaq1280x1024Des_1[] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -}; - -static const SiS_LVDSDesStruct Compaq1280x1024Des_2[] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -}; - -/* Clevo L285/287 (dual-link 1024x768) */ - -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_1[] = -{ - {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x2C,0x12,0x9A,0xAE,0x88,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x38,0x13,0x16,0x0C,0xE6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}} -}; - -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_2[] = -{ - {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}}, - {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0xE0,0x12,0xB1,0x47,0x30,0x71,0x33}}, - {{0x2D,0x12,0x79,0x96,0x70,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}}, - {{0x29,0x12,0xB5,0xD2,0xAC,0xF4,0x12,0xD9,0x47,0x44,0x99,0x33}}, - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, -#if 0 - {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}}, - {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}}, - {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}}, - {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}} -#endif -}; - -static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_3[] = -{ - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, /* Corrected */ - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, - {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, - {{0x25,0x13,0xC9,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}} -}; - -/* CRT2 data is std */ - -static const SiS_LVDSDesStruct Clevo1024x768Des_1[] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -}; - -static const SiS_LVDSDesStruct Clevo1024x768Des_2[] = -{ - { 1184, 622 }, - { 1184, 597 }, - { 1184, 622 }, - { 1184, 597 }, - { 1152, 622 }, - { 1232, 722 }, - { 0, 0 } -}; - /* Asus A2xxxH _2 */ static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Asus1024x768_3[] = @@ -601,52 +424,6 @@ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}} }; -static const SiS_LVDSDesStruct Asus1024x768Des_1[] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -}; - -static const SiS_LVDSDesStruct Asus1024x768Des_2[] = -{ - { 1184, 622 }, - { 1184, 597 }, - { 1184, 622 }, - { 1184, 597 }, - { 1152, 622 }, - { 1232, 722 }, - { 0, 0 } -}; - -/* CRT2 data is std */ - -/* Uniwill N243S9, ECS A928 */ -static const SiS_LVDSDesStruct Uniwill1024x768Des_1[] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 805 } -}; - -static const SiS_LVDSDesStruct Uniwill1024x768Des_2[] = -{ - { 1184, 622 }, - { 1184, 597 }, - { 1184, 622 }, - { 1184, 597 }, - { 1152, 650 }, - { 1232, 722 }, - { 0, 805 }, -}; diff -urN linux-2.4.25/drivers/video/sis/osdef.h linux-2.4.26/drivers/video/sis/osdef.h --- linux-2.4.25/drivers/video/sis/osdef.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/osdef.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -54,95 +51,77 @@ */ /* The choices are: */ - #define LINUX_KERNEL /* Kernel framebuffer */ /* #define LINUX_XF86 */ /* XFree86 */ -/**********************************************************************/ -#ifdef LINUX_KERNEL /* -------------------------- */ -#include -#include - -#ifdef CONFIG_FB_SIS_300 -#define SIS300 -#endif - -#ifdef CONFIG_FB_SIS_315 -#define SIS315H -#endif - -#if 1 -#define SISFBACCEL /* Include 2D acceleration */ -#endif - -#endif - -#ifdef LINUX_XF86 /* ----------------------------- */ -#define SIS300 -#define SIS315H -#endif - -/**********************************************************************/ -#ifdef LINUX_XF86 -#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) -#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) -#endif - -#ifdef LINUX_KERNEL -#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) -#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length) -#endif - -/**********************************************************************/ - #ifdef OutPortByte #undef OutPortByte -#endif /* OutPortByte */ +#endif #ifdef OutPortWord #undef OutPortWord -#endif /* OutPortWord */ +#endif #ifdef OutPortLong #undef OutPortLong -#endif /* OutPortLong */ +#endif #ifdef InPortByte #undef InPortByte -#endif /* InPortByte */ +#endif #ifdef InPortWord #undef InPortWord -#endif /* InPortWord */ +#endif #ifdef InPortLong #undef InPortLong -#endif /* InPortLong */ +#endif /**********************************************************************/ -/* LINUX XF86 */ +/* LINUX KERNEL */ /**********************************************************************/ -#ifdef LINUX_XF86 -#define OutPortByte(p,v) outb((CARD16)(p),(CARD8)(v)) -#define OutPortWord(p,v) outw((CARD16)(p),(CARD16)(v)) -#define OutPortLong(p,v) outl((CARD16)(p),(CARD32)(v)) -#define InPortByte(p) inb((CARD16)(p)) -#define InPortWord(p) inw((CARD16)(p)) -#define InPortLong(p) inl((CARD16)(p)) +#ifdef LINUX_KERNEL +#include +#include + +#ifdef CONFIG_FB_SIS_300 +#define SIS300 +#endif + +#ifdef CONFIG_FB_SIS_315 +#define SIS315H +#endif + +#if 1 +#define SISFBACCEL /* Include 2D acceleration */ +#endif + +#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p)) +#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p)) +#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p)) +#define InPortByte(p) inb((SISIOADDRESS)(p)) +#define InPortWord(p) inw((SISIOADDRESS)(p)) +#define InPortLong(p) inl((SISIOADDRESS)(p)) +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize) #endif /**********************************************************************/ -/* LINUX KERNEL */ +/* XFree86 */ /**********************************************************************/ -#ifdef LINUX_KERNEL -#define OutPortByte(p,v) outb((u8)(v),(u16)(p)) -#define OutPortWord(p,v) outw((u16)(v),(u16)(p)) -#define OutPortLong(p,v) outl((u32)(v),(u16)(p)) -#define InPortByte(p) inb((u16)(p)) -#define InPortWord(p) inw((u16)(p)) -#define InPortLong(p) inl((u16)(p)) +#ifdef LINUX_XF86 +#define SIS300 +#define SIS315H + +#define OutPortByte(p,v) outb((IOADDRESS)(p),(CARD8)(v)) +#define OutPortWord(p,v) outw((IOADDRESS)(p),(CARD16)(v)) +#define OutPortLong(p,v) outl((IOADDRESS)(p),(CARD32)(v)) +#define InPortByte(p) inb((IOADDRESS)(p)) +#define InPortWord(p) inw((IOADDRESS)(p)) +#define InPortLong(p) inl((IOADDRESS)(p)) +#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize) #endif diff -urN linux-2.4.25/drivers/video/sis/sis_accel.c linux-2.4.26/drivers/video/sis/sis_accel.c --- linux-2.4.25/drivers/video/sis/sis_accel.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/sis_accel.c 2004-04-14 06:05:40.000000000 -0700 @@ -77,9 +77,8 @@ #include "sis_accel.h" #include "sis.h" -extern struct video_info ivideo; -extern VGA_ENGINE sisvga_engine; -extern int sisfb_accel; +extern struct video_info ivideo; +extern int sisfb_accel; static const int sisALUConv[] = { @@ -337,7 +336,7 @@ void sisfb_syncaccel(void) { - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 SiS300Sync(); #endif @@ -357,7 +356,7 @@ if(!ivideo.accel) return 0; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 SiS300Sync(); #endif @@ -393,7 +392,7 @@ break; } - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 CRITBEGIN SiS300SetupForSolidFill(col, myrops[rect->rop], 0); @@ -432,7 +431,7 @@ if(area->sy < area->dy) ydir = 0; else ydir = 1; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 CRITBEGIN SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1); @@ -494,7 +493,7 @@ if(srcy < dsty) ydir = 0; else ydir = 1; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 CRITBEGIN SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1); @@ -509,10 +508,6 @@ SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height); CRITEND SiS310Sync(); -#if 0 - printk(KERN_INFO "sis_bmove sx %d sy %d dx %d dy %d w %d h %d\n", - srcx, srcy, dstx, dsty, width, height); -#endif #endif } } @@ -527,7 +522,7 @@ width *= fontwidth(p); height *= fontheight(p); - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 CRITBEGIN SiS300SetupForSolidFill(color, 3, 0); @@ -616,7 +611,7 @@ srcx *= fontwidth(p); srcy *= fontheight(p); - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 CRITBEGIN SiS300SetupForSolidFill(0, 0x0a, 0); diff -urN linux-2.4.25/drivers/video/sis/sis_accel.h linux-2.4.26/drivers/video/sis/sis_accel.h --- linux-2.4.25/drivers/video/sis/sis_accel.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/sis_accel.h 2004-04-14 06:05:40.000000000 -0700 @@ -158,7 +158,15 @@ #define Q_READ_PTR 0x85C8 /* Current read pointer (?) */ #define Q_STATUS 0x85CC /* queue status */ +#define MMIO_IN8(base, offset) readb((base+offset)) +#define MMIO_IN16(base, offset) readw((base+offset)) +#define MMIO_IN32(base, offset) readl((base+offset)) + +#define MMIO_OUT8(base, offset, val) writeb((val), (base+offset)) +#define MMIO_OUT16(base, offset, val) writew((val), (base+offset)) +#define MMIO_OUT32(base, offset, val) writel((val), (base+offset)) +#if 0 #define MMIO_IN8(base, offset) \ *(volatile u8 *)(((u8*)(base)) + (offset)) #define MMIO_IN16(base, offset) \ @@ -171,6 +179,7 @@ *(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val) #define MMIO_OUT32(base, offset, val) \ *(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val) +#endif /* ------------- SiS 300 series -------------- */ diff -urN linux-2.4.25/drivers/video/sis/sis_main.c linux-2.4.26/drivers/video/sis/sis_main.c --- linux-2.4.25/drivers/video/sis/sis_main.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/sis_main.c 2004-04-14 06:05:40.000000000 -0700 @@ -47,9 +47,7 @@ #include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #include -#endif #include #include #include @@ -87,14 +85,18 @@ #include "sis.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -#error "This version of sisfb requires at least 2.6.0" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3) +#error "This version of sisfb requires at least 2.6.3" +#else +#if 0 +#define NEWFBDEV /* Define this as soon as sysfs support has returned */ +#endif #endif #endif /* -------------------- Macro definitions ---------------------------- */ -#undef SISFBDEBUG /* TW: no debugging */ +#undef SISFBDEBUG /* no debugging */ #ifdef SISFBDEBUG #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) @@ -118,170 +120,23 @@ /* --------------- Hardware Access Routines -------------------------- */ -void sisfb_set_reg4(u16 port, unsigned long data) -{ - outl((u32) (data & 0xffffffff), port); -} - -u32 sisfb_get_reg3(u16 port) -{ - u32 data; - - data = inl(port); - return (data); -} - -/* ------------ Interface for init & mode switching code ------------- */ - -BOOLEAN -sisfb_query_VGA_config_space(PSIS_HW_INFO psishw_ext, - unsigned long offset, unsigned long set, unsigned long *value) +/* These are used on x86 hardware during probe only */ +static void __devinit +sisfb_set_reg4(u16 port, u32 data) { - static struct pci_dev *pdev = NULL; - static unsigned char init = 0, valid_pdev = 0; - - if (!set) - DPRINTK("sisfb: Get VGA offset 0x%lx\n", offset); - else - DPRINTK("sisfb: Set offset 0x%lx to 0x%lx\n", offset, *value); - - if (!init) { - init = TRUE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74) - pci_for_each_dev(pdev) { -#else - while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) { -#endif - DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == ivideo.chip_id)) { - valid_pdev = TRUE; - break; - } - } - } - - if (!valid_pdev) { - printk(KERN_DEBUG "sisfb: Can't find SiS %d VGA device.\n", - ivideo.chip_id); - return FALSE; - } - - if (set == 0) - pci_read_config_dword(pdev, offset, (u32 *)value); - else - pci_write_config_dword(pdev, offset, (u32)(*value)); - - return TRUE; + outl((u32)(data & 0xffffffff), port); } -BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_INFO psishw_ext, - unsigned long offset, unsigned long set, unsigned long *value) +static u32 __devinit +sisfb_get_reg3(u16 port) { - static struct pci_dev *pdev = NULL; - static unsigned char init = 0, valid_pdev = 0; - u16 nbridge_id = 0; - - if (!init) { - init = TRUE; - switch (ivideo.chip) { -#ifdef CONFIG_FB_SIS_300 - case SIS_540: - nbridge_id = PCI_DEVICE_ID_SI_540; - break; - case SIS_630: - nbridge_id = PCI_DEVICE_ID_SI_630; - break; - case SIS_730: - nbridge_id = PCI_DEVICE_ID_SI_730; - break; -#endif -#ifdef CONFIG_FB_SIS_315 - case SIS_550: - nbridge_id = PCI_DEVICE_ID_SI_550; - break; - case SIS_650: - nbridge_id = PCI_DEVICE_ID_SI_650; - break; - case SIS_740: - nbridge_id = PCI_DEVICE_ID_SI_740; - break; - case SIS_661: - nbridge_id = PCI_DEVICE_ID_SI_660; - break; - case SIS_741: - nbridge_id = PCI_DEVICE_ID_SI_741; - break; - case SIS_660: - nbridge_id = PCI_DEVICE_ID_SI_660; - break; - case SIS_760: - nbridge_id = PCI_DEVICE_ID_SI_760; - break; -#endif - default: - nbridge_id = 0; - break; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74) - pci_for_each_dev(pdev) { -#else - while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) { -#endif - DPRINTK("Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == nbridge_id)) { - valid_pdev = TRUE; - break; - } - } - } - - if (!valid_pdev) { - printk(KERN_DEBUG "sisfb: Can't find SiS %d North Bridge device.\n", - nbridge_id); - return FALSE; - } - - if (set == 0) - pci_read_config_dword(pdev, offset, (u32 *)value); - else - pci_write_config_dword(pdev, offset, (u32)(*value)); - - return TRUE; + return((u32)inl(port)); } /* ------------------ Internal helper routines ----------------- */ -static BOOLEAN sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate) -{ - int htotal, vtotal; - unsigned int dclock, hsync; - - if(!monitor->datavalid) return TRUE; - - if(mode_idx < 0) return FALSE; - - if(rate < (monitor->vmin - 1)) return FALSE; - if(rate > (monitor->vmax + 1)) return FALSE; - - if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no, - &htotal, &vtotal, rate_idx)) { - dclock = (htotal * vtotal * rate) / 1000; - if(dclock > (monitor->dclockmax + 1000)) return FALSE; - hsync = dclock / htotal; - if(hsync < (monitor->hmin - 1)) return FALSE; - if(hsync > (monitor->hmax + 1)) return FALSE; - } else { - return FALSE; - } - return TRUE; -}; - -static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) +static BOOLEAN __devinit +sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) { int i, j, xres, yres, refresh, index; u32 emodes; @@ -381,7 +236,8 @@ return(monitor->datavalid); } -static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno) +static void __devinit +sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno) { USHORT temp, i, realcrtno = crtno; u8 buffer[256]; @@ -396,7 +252,7 @@ if((sisfb_crt1off) && (!crtno)) return; - temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, realcrtno, 0, &buffer[0]); + temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, ivideo.sisvga_engine, realcrtno, 0, &buffer[0]); if((!temp) || (temp == 0xffff)) { printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1); return; @@ -411,7 +267,7 @@ if(temp & 0x02) { i = 3; /* Number of retrys */ do { - temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, + temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, ivideo.sisvga_engine, realcrtno, 1, &buffer[0]); } while((temp) && i--); if(!temp) { @@ -431,7 +287,8 @@ } } -static void sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet) +static void __init +sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet) { int i = 0, j = 0; @@ -467,7 +324,8 @@ if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode); } -static void sisfb_search_mode(char *name, BOOLEAN quiet) +static void __init +sisfb_search_mode(char *name, BOOLEAN quiet) { int i = 0; unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0; @@ -538,17 +396,145 @@ } -static int sisfb_validate_mode(int myindex, unsigned long vbflags) +static void __init +sisfb_search_crt2type(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while(sis_crt2type[i].type_no != -1) { + if (!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { + sisfb_crt2type = sis_crt2type[i].type_no; + sisfb_tvplug = sis_crt2type[i].tvplug_no; + sisfb_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0; + sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0; + break; + } + i++; + } + if(sisfb_crt2type < 0) + printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name); + if(ivideo.chip != SIS_550) { + sisfb_dstn = sisfb_fstn = 0; + } +} + +static void __init +sisfb_search_queuemode(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while (sis_queuemode[i].type_no != -1) { + if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) { + sisfb_queuemode = sis_queuemode[i].type_no; + break; + } + i++; + } + if (sisfb_queuemode < 0) + printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name); +} + +static void __init +sisfb_search_tvstd(const char *name) +{ + int i = 0; + + if(name == NULL) + return; + + while (sis_tvtype[i].type_no != -1) { + if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { + ivideo.vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN); + ivideo.vbflags |= sis_tvtype[i].type_no; + break; + } + i++; + } +} + +static void __init +sisfb_search_specialtiming(const char *name) +{ + int i = 0; + BOOLEAN found = FALSE; + + if(name == NULL) + return; + + if(!strnicmp(name, "none", 4)) { + SiS_Pr.SiS_CustomT = CUT_FORCENONE; + printk(KERN_DEBUG "sisfb: Special timing disabled\n"); + } else { + while(mycustomttable[i].chipID != 0) { + if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) { + SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; + found = TRUE; + printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", + mycustomttable[i].vendorName, mycustomttable[i].cardName, + mycustomttable[i].optionName); + break; + } + i++; + } + if(!found) { + printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); + printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); + i = 0; + while(mycustomttable[i].chipID != 0) { + printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", + mycustomttable[i].optionName, + mycustomttable[i].vendorName, + mycustomttable[i].cardName); + i++; + } + } + } +} + +static BOOLEAN +sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate) +{ + int htotal, vtotal; + unsigned int dclock, hsync; + + if(!monitor->datavalid) return TRUE; + + if(mode_idx < 0) return FALSE; + + if(rate < (monitor->vmin - 1)) return FALSE; + if(rate > (monitor->vmax + 1)) return FALSE; + + if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no, + &htotal, &vtotal, rate_idx)) { + dclock = (htotal * vtotal * rate) / 1000; + if(dclock > (monitor->dclockmax + 1000)) return FALSE; + hsync = dclock / htotal; + if(hsync < (monitor->hmin - 1)) return FALSE; + if(hsync > (monitor->hmax + 1)) return FALSE; + } else { + return FALSE; + } + return TRUE; +} + +static int +sisfb_validate_mode(int myindex, unsigned long vbflags) { - u16 xres, yres, myres; + u16 xres=0, yres, myres; #ifdef CONFIG_FB_SIS_300 - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1); } #endif #ifdef CONFIG_FB_SIS_315 - if(sisvga_engine == SIS_315_VGA) { + if(ivideo.sisvga_engine == SIS_315_VGA) { if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1); } #endif @@ -557,7 +543,7 @@ switch (vbflags & VB_DISPTYPE_DISP2) { case CRT2_LCD: - switch (sishw_ext.ulCRT2LCDType) { + switch(sishw_ext.ulCRT2LCDType) { case LCD_640x480: xres = 640; yres = 480; break; case LCD_800x600: xres = 800; yres = 600; break; case LCD_1024x600: xres = 1024; yres = 600; break; @@ -571,6 +557,9 @@ case LCD_320x480: xres = 320; yres = 480; break; /* FSTN (old) */ case LCD_640x480_2: case LCD_640x480_3:xres = 640; yres = 480; break; /* FSTN (new) */ + case LCD_1680x1050:xres = 1680; yres = 1050; break; + case LCD_1280x800: xres = 1280; yres = 800; break; + case LCD_1280x720: yres = 1280; yres = 720; break; default: xres = 0; yres = 0; break; } @@ -602,21 +591,21 @@ } } - if(SiS_GetModeID_LCD(sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, + if(SiS_GetModeID_LCD(ivideo.sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0, sisfb_fstn, SiS_Pr.SiS_CustomT, xres, yres) < 0x14) { return(-1); } break; - case CRT2_TV: - if(SiS_GetModeID_TV(sisvga_engine, vbflags, sisbios_mode[myindex].xres, + case CRT2_TV: + if(SiS_GetModeID_TV(ivideo.sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0) < 0x14) { return(-1); } break; case CRT2_VGA: - if(SiS_GetModeID_VGA2(sisvga_engine, vbflags, sisbios_mode[myindex].xres, + if(SiS_GetModeID_VGA2(ivideo.sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres, 0) < 0x14) { return(-1); } @@ -626,49 +615,9 @@ return(myindex); } -static void sisfb_search_crt2type(const char *name) -{ - int i = 0; - if(name == NULL) - return; - - while(sis_crt2type[i].type_no != -1) { - if (!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) { - sisfb_crt2type = sis_crt2type[i].type_no; - sisfb_tvplug = sis_crt2type[i].tvplug_no; - sisfb_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0; - sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0; - break; - } - i++; - } - if(sisfb_crt2type < 0) - printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name); - if(ivideo.chip != SIS_550) { - sisfb_dstn = sisfb_fstn = 0; - } -} - -static void sisfb_search_queuemode(const char *name) -{ - int i = 0; - - if(name == NULL) - return; - - while (sis_queuemode[i].type_no != -1) { - if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) { - sisfb_queuemode = sis_queuemode[i].type_no; - break; - } - i++; - } - if (sisfb_queuemode < 0) - printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name); -} - -static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx) +static u8 +sisfb_search_refresh_rate(unsigned int rate, int mode_idx) { u16 xres, yres; int i = 0; @@ -676,37 +625,37 @@ xres = sisbios_mode[mode_idx].xres; yres = sisbios_mode[mode_idx].yres; - sisfb_rate_idx = 0; + ivideo.rate_idx = 0; while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) { if ((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) { if (sisfb_vrate[i].refresh == rate) { - sisfb_rate_idx = sisfb_vrate[i].idx; + ivideo.rate_idx = sisfb_vrate[i].idx; break; } else if (sisfb_vrate[i].refresh > rate) { if ((sisfb_vrate[i].refresh - rate) <= 3) { DPRINTK("sisfb: Adjusting rate from %d up to %d\n", rate, sisfb_vrate[i].refresh); - sisfb_rate_idx = sisfb_vrate[i].idx; + ivideo.rate_idx = sisfb_vrate[i].idx; ivideo.refresh_rate = sisfb_vrate[i].refresh; } else if (((rate - sisfb_vrate[i-1].refresh) <= 2) && (sisfb_vrate[i].idx != 1)) { DPRINTK("sisfb: Adjusting rate from %d down to %d\n", rate, sisfb_vrate[i-1].refresh); - sisfb_rate_idx = sisfb_vrate[i-1].idx; + ivideo.rate_idx = sisfb_vrate[i-1].idx; ivideo.refresh_rate = sisfb_vrate[i-1].refresh; } break; } else if((rate - sisfb_vrate[i].refresh) <= 2) { DPRINTK("sisfb: Adjusting rate from %d down to %d\n", rate, sisfb_vrate[i].refresh); - sisfb_rate_idx = sisfb_vrate[i].idx; + ivideo.rate_idx = sisfb_vrate[i].idx; break; } } i++; } - if (sisfb_rate_idx > 0) { - return sisfb_rate_idx; + if(ivideo.rate_idx > 0) { + return ivideo.rate_idx; } else { printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n", rate, xres, yres); @@ -714,78 +663,27 @@ } } -static void sisfb_search_tvstd(const char *name) -{ - int i = 0; - - if(name == NULL) - return; - - while (sis_tvtype[i].type_no != -1) { - if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) { - ivideo.vbflags |= sis_tvtype[i].type_no; - break; - } - i++; - } -} - -static void sisfb_search_specialtiming(const char *name) -{ - int i = 0; - BOOLEAN found = FALSE; - - if(name == NULL) - return; - - if(!strnicmp(name, "none", 4)) { - SiS_Pr.SiS_CustomT = CUT_FORCENONE; - printk(KERN_DEBUG "sisfb: Special timing disabled\n"); - } else { - while(mycustomttable[i].chipID != 0) { - if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) { - SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID; - found = TRUE; - printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n", - mycustomttable[i].vendorName, mycustomttable[i].cardName, - mycustomttable[i].optionName); - break; - } - i++; - } - if(!found) { - printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:"); - printk(KERN_WARNING "\t\"none\" (to disable special timings)\n"); - i = 0; - while(mycustomttable[i].chipID != 0) { - printk(KERN_WARNING "\t\"%s\" (for %s %s)\n", - mycustomttable[i].optionName, - mycustomttable[i].vendorName, - mycustomttable[i].cardName); - i++; - } - } - } -} -static BOOLEAN sisfb_bridgeisslave(void) +static BOOLEAN +sisfb_bridgeisslave(void) { unsigned char P1_00; if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE; inSISIDXREG(SISPART1,0x00,P1_00); - if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || - ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { + if( ((ivideo.sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) || + ((ivideo.sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) { return TRUE; } else { return FALSE; } } -static BOOLEAN sisfballowretracecrt1(void) +static BOOLEAN +sisfballowretracecrt1(void) { - unsigned char temp; + u8 temp; inSISIDXREG(SISCR,0x17,temp); if(!(temp & 0x80)) return FALSE; @@ -796,16 +694,17 @@ return TRUE; } -static BOOLEAN sisfbcheckvretracecrt1(void) +static BOOLEAN +sisfbcheckvretracecrt1(void) { - if(!sisfballowretracecrt1()) return FALSE; if(inSISREG(SISINPSTAT) & 0x08) return TRUE; else return FALSE; } -static void sisfbwaitretracecrt1(void) +static void +sisfbwaitretracecrt1(void) { int watchdog; @@ -817,11 +716,12 @@ while((inSISREG(SISINPSTAT) & 0x08) && --watchdog); } -static BOOLEAN sisfbcheckvretracecrt2(void) +static BOOLEAN +sisfbcheckvretracecrt2(void) { unsigned char temp, reg; - switch(sisvga_engine) { + switch(ivideo.sisvga_engine) { case SIS_300_VGA: reg = 0x25; break; @@ -837,7 +737,8 @@ else return TRUE; } -static BOOLEAN sisfb_CheckVBRetrace(void) +static BOOLEAN +sisfb_CheckVBRetrace(void) { if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { if(sisfb_bridgeisslave()) { @@ -849,7 +750,8 @@ return(sisfbcheckvretracecrt1()); } -static int sisfb_myblank(int blank) +static int +sisfb_myblank(int blank) { u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13; BOOLEAN backlight = TRUE; @@ -912,8 +814,8 @@ ((sisfb_thismonitor.datavalid) && (sisfb_thismonitor.feature & 0xe0))) { - if(sisvga_engine == SIS_315_VGA) { - setSISIDXREG(SISCR, 0x63, 0xbf, cr63); + if(ivideo.sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, 0xbf, cr63); } setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f); @@ -929,7 +831,7 @@ } else { SiS_SiS30xBLOff(&SiS_Pr, &sishw_ext); } - } else if(sisvga_engine == SIS_315_VGA) { + } else if(ivideo.sisvga_engine == SIS_315_VGA) { if(ivideo.vbflags & VB_CHRONTEL) { if(backlight) { SiS_Chrontel701xBLOn(&SiS_Pr,&sishw_ext); @@ -939,19 +841,19 @@ } } - if(((sisvga_engine == SIS_300_VGA) && + if(((ivideo.sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & (VB_301|VB_30xBDH|VB_LVDS))) || - ((sisvga_engine == SIS_315_VGA) && + ((ivideo.sisvga_engine == SIS_315_VGA) && ((ivideo.vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) { setSISIDXREG(SISSR, 0x11, ~0x0c, sr11); } - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) && (!(ivideo.vbflags & VB_30xBDH))) { setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13); } - } else if(sisvga_engine == SIS_315_VGA) { + } else if(ivideo.sisvga_engine == SIS_315_VGA) { if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) && (!(ivideo.vbflags & VB_30xBDH))) { setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0); @@ -971,7 +873,8 @@ /* ----------- FBDev related routines for all series ----------- */ -static void sisfb_set_vparms(void) +static void +sisfb_set_vparms(void) { switch(ivideo.video_bpp) { case 8: @@ -997,7 +900,8 @@ } } -static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, +static int +sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info) { unsigned int htotal = 0, vtotal = 0; @@ -1034,11 +938,6 @@ ivideo.refresh_rate = (unsigned int) (hrate * 2 / vtotal); } else ivideo.refresh_rate = 60; -#if 0 - printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n", - var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate); -#endif - old_mode = sisfb_mode_idx; sisfb_mode_idx = 0; @@ -1047,7 +946,7 @@ if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) && (sisbios_mode[sisfb_mode_idx].yres == var->yres) && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) { - sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; + ivideo.mode_no = sisbios_mode[sisfb_mode_idx].mode_no; found_mode = 1; break; } @@ -1067,14 +966,14 @@ } if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) { - sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; + ivideo.rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) if(sisfb_thismonitor.datavalid) { if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx, - sisfb_rate_idx, ivideo.refresh_rate)) { + ivideo.rate_idx, ivideo.refresh_rate)) { printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); } } @@ -1087,8 +986,8 @@ #endif sisfb_pre_setmode(); - if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) { - printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no); + if(SiSSetMode(&SiS_Pr, &sishw_ext, ivideo.mode_no) == 0) { + printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo.mode_no); return -EINVAL; } @@ -1114,7 +1013,7 @@ ivideo.current_pixclock = var->pixclock; ivideo.current_refresh_rate = ivideo.refresh_rate; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate; + sisfb_lastrates[ivideo.mode_no] = ivideo.refresh_rate; #endif sisfb_post_setmode(); @@ -1123,7 +1022,8 @@ return 0; } -static int sisfb_pan_var(struct fb_var_screeninfo *var) +static int +sisfb_pan_var(struct fb_var_screeninfo *var) { unsigned int base; @@ -1154,22 +1054,23 @@ outSISIDXREG(SISCR, 0x0D, base & 0xFF); outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF); outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF); - if(sisvga_engine == SIS_315_VGA) { + if(ivideo.sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01); } if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { - orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01); + orSISIDXREG(SISPART1, ivideo.CRT2_write_enable, 0x01); outSISIDXREG(SISPART1, 0x06, (base & 0xFF)); outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF)); outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF)); - if(sisvga_engine == SIS_315_VGA) { + if(ivideo.sisvga_engine == SIS_315_VGA) { setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7); } } return 0; } -static void sisfb_bpp_to_var(struct fb_var_screeninfo *var) +static void +sisfb_bpp_to_var(struct fb_var_screeninfo *var) { switch(var->bits_per_pixel) { case 8: @@ -1202,7 +1103,8 @@ } } -void sis_dispinfo(struct ap_data *rec) +void +sis_dispinfo(struct ap_data *rec) { rec->minfo.bpp = ivideo.video_bpp; rec->minfo.xres = ivideo.video_width; @@ -1228,7 +1130,8 @@ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) -static void sisfb_crtc_to_var(struct fb_var_screeninfo *var) +static void +sisfb_crtc_to_var(struct fb_var_screeninfo *var) { u16 VRE, VBE, VRS, VBS, VDE, VT; u16 HRE, HBE, HRS, HBS, HDE, HT; @@ -1417,10 +1320,11 @@ } -static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, +static int +sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue, unsigned *transp, struct fb_info *fb_info) { - if (regno >= ivideo.video_cmap_len) + if(regno >= ivideo.video_cmap_len) return 1; *red = sis_palette[regno].red; @@ -1430,24 +1334,25 @@ return 0; } -static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, +static int +sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fb_info) { - if (regno >= ivideo.video_cmap_len) + if(regno >= ivideo.video_cmap_len) return 1; sis_palette[regno].red = red; sis_palette[regno].green = green; sis_palette[regno].blue = blue; - switch (ivideo.video_bpp) { + switch(ivideo.video_bpp) { #ifdef FBCON_HAS_CFB8 case 8: outSISREG(SISDACA, regno); outSISREG(SISDACD, (red >> 10)); outSISREG(SISDACD, (green >> 10)); outSISREG(SISDACD, (blue >> 10)); - if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) { + if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { outSISREG(SISDAC2A, regno); outSISREG(SISDAC2D, (red >> 8)); outSISREG(SISDAC2D, (green >> 8)); @@ -1473,7 +1378,8 @@ return 0; } -static void sisfb_set_disp(int con, struct fb_var_screeninfo *var, +static void +sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info) { struct fb_fix_screeninfo fix; @@ -1502,7 +1408,7 @@ save_flags(flags); - switch (ivideo.video_bpp) { + switch(ivideo.video_bpp) { #ifdef FBCON_HAS_CFB8 case 8: #ifdef SISFBACCEL @@ -1548,12 +1454,13 @@ } } -static void sisfb_do_install_cmap(int con, struct fb_info *info) +static void +sisfb_do_install_cmap(int con, struct fb_info *info) { - if (con != currcon) + if(con != currcon) return; - if (fb_display[con].cmap.len) + if(fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info); else fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, @@ -1561,7 +1468,8 @@ } -static int sisfb_get_var(struct fb_var_screeninfo *var, int con, +static int +sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { if(con == -1) @@ -1577,7 +1485,8 @@ return 0; } -static int sisfb_set_var(struct fb_var_screeninfo *var, int con, +static int +sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { int err; @@ -1611,10 +1520,11 @@ return 0; } -static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, +static int +sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { - if (con == currcon) + if(con == currcon) return fb_get_cmap(cmap, kspc, sis_getcolreg, info); else if (fb_display[con].cmap.len) @@ -1625,18 +1535,19 @@ return 0; } -static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, +static int +sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) { int err; - if (!fb_display[con].cmap.len) { + if(!fb_display[con].cmap.len) { err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0); if (err) return err; } - if (con == currcon) + if(con == currcon) return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info); else @@ -1645,17 +1556,18 @@ return 0; } -static int sisfb_pan_display(struct fb_var_screeninfo *var, int con, +static int +sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info) { int err; - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) + if(var->vmode & FB_VMODE_YWRAP) { + if(var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) return -EINVAL; } else { - if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || - var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) + if(var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || + var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) return -EINVAL; } @@ -1665,7 +1577,7 @@ fb_display[con].var.xoffset = var->xoffset; fb_display[con].var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) + if(var->vmode & FB_VMODE_YWRAP) fb_display[con].var.vmode |= FB_VMODE_YWRAP; else fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; @@ -1673,15 +1585,16 @@ return 0; } -static int sisfb_mmap(struct fb_info *info, struct file *file, +static int +sisfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) { struct fb_var_screeninfo var; unsigned long start; unsigned long off; - u32 len, mmio_off; + unsigned long len, mmio_off; - if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; + if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; @@ -1701,7 +1614,7 @@ if(var.accel_flags) return -EINVAL; start = (unsigned long) ivideo.mmio_base; - len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size); + len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.mmio_size); } start &= PAGE_MASK; @@ -1712,18 +1625,19 @@ vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */ #if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3) + if(boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; #endif /* RedHat requires vma as the first paramater to the following call */ - if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, - vma->vm_page_prot)) + if(io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start, + vma->vm_page_prot)) return -EAGAIN; return 0; } -static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly) +static void +sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly) { struct display *p = &fb_display[currcon]; u16 c; @@ -1737,7 +1651,7 @@ widthb = (fontwidth(p) + 7) / 8; c = gly->ch & p->charmask; - if (fontwidth(p) <= 8) + if(fontwidth(p) <= 8) cdat = p->fontdata + c * fontheight(p); else cdat = p->fontdata + (c * fontheight(p) << 1); @@ -1747,12 +1661,14 @@ gly->ngmask = size; } -static int sisfb_update_var(int con, struct fb_info *info) +static int +sisfb_update_var(int con, struct fb_info *info) { return(sisfb_pan_var(&fb_display[con].var)); } -static int sisfb_switch(int con, struct fb_info *info) +static int +sisfb_switch(int con, struct fb_info *info) { int cols, rows; @@ -1784,7 +1700,8 @@ return 1; } -static void sisfb_blank(int blank, struct fb_info *info) +static void +sisfb_blank(int blank, struct fb_info *info) { sisfb_myblank(blank); } @@ -1794,17 +1711,20 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -static int sisfb_open(struct fb_info *info, int user) +static int +sisfb_open(struct fb_info *info, int user) { return 0; } -static int sisfb_release(struct fb_info *info, int user) +static int +sisfb_release(struct fb_info *info, int user) { return 0; } -static int sisfb_get_cmap_len(const struct fb_var_screeninfo *var) +static int +sisfb_get_cmap_len(const struct fb_var_screeninfo *var) { int rc = 16; @@ -1820,19 +1740,20 @@ return rc; } -static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) +static int +sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info) { - if (regno >= sisfb_get_cmap_len(&info->var)) + if(regno >= sisfb_get_cmap_len(&info->var)) return 1; - switch (info->var.bits_per_pixel) { + switch(info->var.bits_per_pixel) { case 8: outSISREG(SISDACA, regno); outSISREG(SISDACD, (red >> 10)); outSISREG(SISDACD, (green >> 10)); outSISREG(SISDACD, (blue >> 10)); - if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) { + if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { outSISREG(SISDAC2A, regno); outSISREG(SISDAC2D, (red >> 8)); outSISREG(SISDAC2D, (green >> 8)); @@ -1854,7 +1775,8 @@ return 0; } -static int sisfb_set_par(struct fb_info *info) +static int +sisfb_set_par(struct fb_info *info) { int err; @@ -1866,8 +1788,9 @@ return 0; } -static int sisfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +static int +sisfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) { unsigned int htotal = 0, vtotal = 0, myrateindex = 0; unsigned int drate = 0, hrate = 0, maxyres; @@ -1912,7 +1835,6 @@ } if(!found_mode) { - search_idx = 0; while(sisbios_mode[search_idx].mode_no != 0) { if( (var->xres <= sisbios_mode[search_idx].xres) && @@ -2051,32 +1973,33 @@ return 0; } -static int sisfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info* info) +static int +sisfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info* info) { int err; - if (var->xoffset > (var->xres_virtual - var->xres)) + if(var->xoffset > (var->xres_virtual - var->xres)) return -EINVAL; - if (var->yoffset > (var->yres_virtual - var->yres)) + if(var->yoffset > (var->yres_virtual - var->yres)) return -EINVAL; - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || - var->yoffset >= info->var.yres_virtual || - var->xoffset) + if(var->vmode & FB_VMODE_YWRAP) { + if(var->yoffset < 0 || + var->yoffset >= info->var.yres_virtual || + var->xoffset) return -EINVAL; } else { - if (var->xoffset + info->var.xres > info->var.xres_virtual || - var->yoffset + info->var.yres > info->var.yres_virtual) + if(var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } - + if((err = sisfb_pan_var(var)) < 0) return err; info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) + if(var->vmode & FB_VMODE_YWRAP) info->var.vmode |= FB_VMODE_YWRAP; else info->var.vmode &= ~FB_VMODE_YWRAP; @@ -2084,12 +2007,13 @@ return 0; } -static int sisfb_mmap(struct fb_info *info, struct file *file, +static int +sisfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) { unsigned long start; unsigned long off; - u32 len, mmio_off; + unsigned long len, mmio_off; if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; @@ -2110,7 +2034,7 @@ if(info->var.accel_flags) return -EINVAL; start = (unsigned long) ivideo.mmio_base; - len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size); + len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.mmio_size); } start &= PAGE_MASK; @@ -2131,7 +2055,8 @@ return 0; } -static int sisfb_blank(int blank, struct fb_info *info) +static int +sisfb_blank(int blank, struct fb_info *info) { return(sisfb_myblank(blank)); } @@ -2207,8 +2132,8 @@ { unsigned long myhwcoffset = 0; - if(sisfb_caps & HW_CURSOR_CAP) - myhwcoffset = sisfb_hwcursor_vbase - + if(ivideo.caps & HW_CURSOR_CAP) + myhwcoffset = ivideo.hwcursor_vbase - (unsigned long) ivideo.video_vbase; return put_user(myhwcoffset, (unsigned long *)arg); @@ -2231,14 +2156,19 @@ x.chip_id = ivideo.chip_id; x.memory = ivideo.video_size / 1024; x.heapstart = ivideo.heapstart / 1024; - x.fbvidmode = sisfb_mode_no; - x.sisfb_caps = sisfb_caps; + if(ivideo.modechanged) { + x.fbvidmode = ivideo.mode_no; + } else { + x.fbvidmode = ivideo.modeprechange; + } + x.sisfb_caps = ivideo.caps; x.sisfb_tqlen = 512; /* yet fixed */ x.sisfb_pcibus = ivideo.pcibus; x.sisfb_pcislot = ivideo.pcislot; x.sisfb_pcifunc = ivideo.pcifunc; - x.sisfb_lcdpdc = sisfb_detectedpdc; - x.sisfb_lcda = sisfb_detectedlcda; + x.sisfb_lcdpdc = ivideo.detectedpdc; + x.sisfb_lcdpdca = ivideo.detectedpdca; + x.sisfb_lcda = ivideo.detectedlcda; x.sisfb_vbflags = ivideo.vbflags; x.sisfb_currentvbflags = ivideo.currentvbflags; x.sisfb_scalelcd = SiS_Pr.UsePanelScaler; @@ -2287,8 +2217,9 @@ } -static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *info) +static int +sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); @@ -2301,7 +2232,7 @@ fix->smem_start = ivideo.video_base; if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if(ivideo.video_size > 0x1000000) { fix->smem_len = 0xc00000; } else if(ivideo.video_size > 0x800000) @@ -2327,8 +2258,8 @@ fix->ywrapstep = 0; fix->line_length = ivideo.video_linelength; fix->mmio_start = ivideo.mmio_base; - fix->mmio_len = sisfb_mmio_size; - if(sisvga_engine == SIS_300_VGA) + fix->mmio_len = ivideo.mmio_size; + if(ivideo.sisvga_engine == SIS_300_VGA) fix->accel = FB_ACCEL_SIS_GLAMOUR; else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_760)) fix->accel = FB_ACCEL_SIS_XABRE; @@ -2338,7 +2269,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) fix->reserved[0] = ivideo.video_size & 0xFFFF; fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF; - fix->reserved[2] = sisfb_caps; + fix->reserved[2] = ivideo.caps; #endif return 0; @@ -2386,14 +2317,14 @@ #ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */ -static int sisfb_get_dram_size_300(void) +static int __devinit sisfb_get_dram_size_300(void) { struct pci_dev *pdev = NULL; int pdev_valid = 0; u8 pci_data, reg; u16 nbridge_id; - switch (ivideo.chip) { + switch(ivideo.chip) { case SIS_540: nbridge_id = PCI_DEVICE_ID_SI_540; break; @@ -2408,7 +2339,7 @@ break; } - if (nbridge_id == 0) { /* 300 */ + if(nbridge_id == 0) { /* 300 */ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg); ivideo.video_size = @@ -2427,7 +2358,7 @@ pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; ivideo.video_size = (unsigned int)(1 << (pci_data+21)); pdev_valid = 1; - + reg = SIS_DATA_BUS_64 << 6; switch (pci_data) { case BRI_DRAM_SIZE_2MB: @@ -2464,7 +2395,7 @@ #ifdef CONFIG_FB_SIS_315 /* for SiS 315/550/650/740/330/661/741/760 */ -static int sisfb_get_dram_size_315(void) +static int __devinit sisfb_get_dram_size_315(void) { u8 reg = 0; @@ -2480,9 +2411,7 @@ return 0; } else if(ivideo.chip == SIS_661 || - ivideo.chip == SIS_741 || - ivideo.chip == SIS_660 || - ivideo.chip == SIS_760) { + ivideo.chip == SIS_741) { inSISIDXREG(SISCR, 0x79, reg); reg &= 0xf0; @@ -2490,6 +2419,22 @@ ivideo.video_size = (1 << reg) << 20; return 0; + } else if(ivideo.chip == SIS_660 || + ivideo.chip == SIS_760) { + + ivideo.video_size = 0; + inSISIDXREG(SISCR, 0x79, reg); + reg &= 0xf0; + reg >>= 4; + if(reg) ivideo.video_size = (1 << reg) << 20; + inSISIDXREG(SISCR, 0x78, reg); + reg &= 0x30; + if(reg) { + if(reg == 0x10) ivideo.video_size += (32 << 20); + else ivideo.video_size += (64 << 20); + } + return 0; + } else { /* 315, 330 */ inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); @@ -2529,38 +2474,18 @@ /* -------------- video bridge detection --------------- */ -static void sisfb_detect_VB_connect() +static void __devinit sisfb_detect_VB_connect() { u8 sr16, sr17, cr32, temp; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17); if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) { - - /* Old BIOSes store the detected CRT2 type in SR17 - * instead of CR32. However, since our detection - * routines store their results to CR32, we now copy - * the remaining bits (for LCD and VGA) to CR32 for - * unified usage. - * SR17[0] CRT1 [1] LCD [2] TV [3] VGA2 - * [4] AVIDEO [5] SVIDEO - */ - -#if 0 - if (sr17 & 0x01) orSISIDXREG(SISCR, 0x32, SIS_CRT1); - else andSISIDXREG(SISCR, 0x32, ~SIS_CRT1); - - if (sr17 & 0x02) orSISIDXREG(SISCR, 0x32, SIS_VB_LCD); - else andSISIDXREG(SISCR, 0x32, ~SIS_VB_LCD); - /* no HiVision and no DVI connector here */ - andSISIDXREG(SISCR, 0x32, ~0xc0); -#endif - /* PAL/NTSC is stored on SR16 on such machines */ - if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) { + if (!(ivideo.vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) { inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16); if (sr16 & 0x20) ivideo.vbflags |= TV_PAL; @@ -2574,69 +2499,54 @@ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32); - if (cr32 & SIS_CRT1) + if(cr32 & SIS_CRT1) { sisfb_crt1off = 0; - else { - if (cr32 & 0x5F) - sisfb_crt1off = 1; - else - sisfb_crt1off = 0; + } else { + if (cr32 & 0x5F) sisfb_crt1off = 1; + else sisfb_crt1off = 0; } ivideo.vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA); - if (cr32 & SIS_VB_TV) - ivideo.vbflags |= CRT2_TV; - if (cr32 & SIS_VB_LCD) - ivideo.vbflags |= CRT2_LCD; - if (cr32 & SIS_VB_CRT2) - ivideo.vbflags |= CRT2_VGA; + if(cr32 & SIS_VB_TV) ivideo.vbflags |= CRT2_TV; + if(cr32 & SIS_VB_LCD) ivideo.vbflags |= CRT2_LCD; + if(cr32 & SIS_VB_CRT2) ivideo.vbflags |= CRT2_VGA; - /* TW: Detect/set TV plug & type */ - if(sisfb_tvplug != -1) - ivideo.vbflags |= sisfb_tvplug; + /* Detect/set TV plug & type */ + if(sisfb_tvplug != -1) ivideo.vbflags |= sisfb_tvplug; - if (cr32 & SIS_VB_SVIDEO) - ivideo.vbflags |= TV_SVIDEO; - else if (cr32 & SIS_VB_COMPOSITE) - ivideo.vbflags |= TV_AVIDEO; - else if (cr32 & SIS_VB_SCART) - ivideo.vbflags |= TV_SCART; - - if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) { - if(sisvga_engine == SIS_300_VGA) { + if(cr32 & SIS_VB_SVIDEO) ivideo.vbflags |= TV_SVIDEO; + else if (cr32 & SIS_VB_COMPOSITE) ivideo.vbflags |= TV_AVIDEO; + else if (cr32 & SIS_VB_SCART) { + ivideo.vbflags |= (TV_SCART | TV_PAL); + ivideo.vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN); + } + + if(!(ivideo.vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) { + if(ivideo.sisvga_engine == SIS_300_VGA) { inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp); - if (temp & 0x01) - ivideo.vbflags |= TV_PAL; - else - ivideo.vbflags |= TV_NTSC; + if(temp & 0x01) ivideo.vbflags |= TV_PAL; + else ivideo.vbflags |= TV_NTSC; } else if((ivideo.chip <= SIS_315PRO) || (ivideo.chip >= SIS_330)) { - inSISIDXREG(SISSR, 0x38, temp); - if(temp & 0x01) - ivideo.vbflags |= TV_PAL; - else - ivideo.vbflags |= TV_NTSC; - + if(temp & 0x01) ivideo.vbflags |= TV_PAL; + else ivideo.vbflags |= TV_NTSC; } else { - inSISIDXREG(SISCR, 0x79, temp); - if(temp & 0x20) - ivideo.vbflags |= TV_PAL; - else - ivideo.vbflags |= TV_NTSC; + if(temp & 0x20) ivideo.vbflags |= TV_PAL; + else ivideo.vbflags |= TV_NTSC; } } - /* TW: Copy forceCRT1 option to CRT1off if option is given */ - if (sisfb_forcecrt1 != -1) { + /* Copy forceCRT1 option to CRT1off if option is given */ + if(sisfb_forcecrt1 != -1) { if(sisfb_forcecrt1) sisfb_crt1off = 0; else sisfb_crt1off = 1; } } -static void sisfb_get_VB_type(void) +static void __devinit sisfb_get_VB_type(void) { u8 vb_chipid; u8 reg; @@ -2648,7 +2558,6 @@ ivideo.hasVB = HASVB_NONE; sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN; sishw_ext.Is301BDH = FALSE; - sishw_ext.usExternalChip = 0; inSISIDXREG(SISPART4, 0x00, vb_chipid); switch (vb_chipid) { @@ -2693,27 +2602,9 @@ break; case 0x02: ivideo.hasVB = HASVB_302; - inSISIDXREG(SISPART4, 0x01, reg); - if(reg < 0xd0) { - ivideo.vbflags |= VB_302B; - sishw_ext.ujVBChipID = VB_CHIP_302B; - inSISIDXREG(SISPART4,0x23,reg); - if(!(reg & 0x02)) { - sishw_ext.Is301BDH = TRUE; - ivideo.vbflags |= VB_30xBDH; - printk(KERN_INFO "%s SiS302B-DH %s\n", stdstr, bridgestr); - } else { - printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); - } - } else if(reg < 0xe0) { - ivideo.vbflags |= VB_301LV; - sishw_ext.ujVBChipID = VB_CHIP_301LV; - printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr); - } else if(reg <= 0xe1) { - ivideo.vbflags |= VB_302LV; - sishw_ext.ujVBChipID = VB_CHIP_302LV; - printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr); - } + ivideo.vbflags |= VB_302B; + sishw_ext.ujVBChipID = VB_CHIP_302B; + printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr); break; } @@ -2721,49 +2612,70 @@ inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg); reg &= SIS_EXTERNAL_CHIP_MASK; reg >>= 1; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { +#ifdef CONFIG_FB_SIS_300 switch (reg) { case SIS_EXTERNAL_CHIP_LVDS: ivideo.hasVB = HASVB_LVDS; ivideo.vbflags |= VB_LVDS; - sishw_ext.usExternalChip = 0x01; printk(KERN_INFO "%s %s\n", stdstr, lvdsstr); break; case SIS_EXTERNAL_CHIP_TRUMPION: ivideo.hasVB = HASVB_TRUMPION; - sishw_ext.usExternalChip = 0x02; + ivideo.vbflags |= VB_TRUMPION; printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr); break; case SIS_EXTERNAL_CHIP_CHRONTEL: ivideo.hasVB = HASVB_CHRONTEL; ivideo.vbflags |= VB_CHRONTEL; - sishw_ext.usExternalChip = 0x04; printk(KERN_INFO "%s %s\n", stdstr, chrstr); break; case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: ivideo.hasVB = HASVB_LVDS_CHRONTEL; ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL); - sishw_ext.usExternalChip = 0x05; printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr); break; } +#endif } else if(ivideo.chip < SIS_661) { +#ifdef CONFIG_FB_SIS_315 switch (reg) { case SIS310_EXTERNAL_CHIP_LVDS: ivideo.hasVB = HASVB_LVDS; ivideo.vbflags |= VB_LVDS; - sishw_ext.usExternalChip = 0x01; printk(KERN_INFO "%s %s\n", stdstr, lvdsstr); break; case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: ivideo.hasVB = HASVB_LVDS_CHRONTEL; ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL); - sishw_ext.usExternalChip = 0x05; printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr); break; } +#endif + } else if(ivideo.chip >= SIS_661) { +#ifdef CONFIG_FB_SIS_315 + inSISIDXREG(SISCR, 0x38, reg); + reg >>= 5; + switch(reg) { + case 0x02: + ivideo.hasVB = HASVB_LVDS; + ivideo.vbflags |= VB_LVDS; + printk(KERN_INFO "%s %s\n", stdstr, lvdsstr); + break; + case 0x03: + ivideo.hasVB = HASVB_LVDS_CHRONTEL; + ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL); + printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr); + break; + case 0x04: + ivideo.hasVB = HASVB_NONE; + ivideo.vbflags |= (VB_LVDS | VB_CONEXANT); + printk(KERN_INFO "%s Conexant video bridge\n", stdstr); + break; + } +#endif } - + } if(ivideo.vbflags & VB_SISBRIDGE) { @@ -2776,8 +2688,7 @@ /* ------------------ Sensing routines ------------------ */ -static BOOLEAN -sisfb_test_DDC1(void) +static BOOLEAN __devinit sisfb_test_DDC1(void) { unsigned short old; int count = 48; @@ -2789,8 +2700,7 @@ return (count == -1) ? FALSE : TRUE; } -static void -sisfb_sense_crt1(void) +static void __devinit sisfb_sense_crt1(void) { unsigned char SR1F, CR63=0, CR17; unsigned short temp = 0xffff; @@ -2802,10 +2712,10 @@ andSISIDXREG(SISSR,0x1F,0x3F); if(SR1F & 0xc0) mustwait = TRUE; - if(sisvga_engine == SIS_315_VGA) { - inSISIDXREG(SISCR,0x63,CR63); + if(ivideo.sisvga_engine == SIS_315_VGA) { + inSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,CR63); CR63 &= 0x40; - andSISIDXREG(SISCR,0x63,0xBF); + andSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF); } inSISIDXREG(SISCR,0x17,CR17); @@ -2823,7 +2733,7 @@ i = 3; do { - temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, 0, 0, NULL); + temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, ivideo.sisvga_engine, 0, 0, NULL); } while(((temp == 0) || (temp == 0xffff)) && i--); if((temp == 0) || (temp == 0xffff)) { @@ -2834,8 +2744,8 @@ orSISIDXREG(SISCR,0x32,0x20); } - if(sisvga_engine == SIS_315_VGA) { - setSISIDXREG(SISCR,0x63,0xBF,CR63); + if(ivideo.sisvga_engine == SIS_315_VGA) { + setSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF,CR63); } setSISIDXREG(SISCR,0x17,0x7F,CR17); @@ -2844,8 +2754,7 @@ } /* Determine and detect attached devices on SiS30x */ -int -SISDoSense(int tempbl, int tempbh, int tempcl, int tempch) +static int __devinit SISDoSense(int tempbl, int tempbh, int tempcl, int tempch) { int temp; @@ -2860,8 +2769,7 @@ return((temp == tempch)); } -void -SiS_Sense30x(void) +static void __devinit SiS_Sense30x(void) { u8 backupP4_0d,backupP2_00; u8 svhs_bl, svhs_bh; @@ -2880,7 +2788,7 @@ inSISIDXREG(SISPART2,0x00,backupP2_00); outSISIDXREG(SISPART2,0x00,(backupP2_00 | 0x1c)); - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV)) { vga2_bh = 0x01; vga2_bl = 0x90; @@ -2890,20 +2798,21 @@ vga2_bh = 0x00; vga2_bl = 0xd1; svhs_bh = 0x00; svhs_bl = 0xb9; cvbs_bh = 0x00; cvbs_bl = 0xb3; + inSISIDXREG(SISPART4,0x01,myflag); + if(myflag & 0x04) { + vga2_bh = 0x00; vga2_bl = 0xfd; + svhs_bh = 0x00; svhs_bl = 0xdd; + cvbs_bh = 0x00; cvbs_bl = 0xee; + } } - inSISIDXREG(SISPART4,0x01,myflag); - if(myflag & 0x04) { - vga2_bh = 0x00; vga2_bl = 0xfd; - svhs_bh = 0x00; svhs_bl = 0xdd; - cvbs_bh = 0x00; cvbs_bl = 0xee; - } + vga2_ch = 0x0e; vga2_cl = 0x08; svhs_ch = 0x04; svhs_cl = 0x04; cvbs_ch = 0x08; cvbs_cl = 0x04; if(ivideo.vbflags & (VB_301LV|VB_302LV)) { vga2_bh = 0x00; vga2_bl = 0x00; vga2_ch = 0x00; vga2_cl = 0x00; - } + } if(ivideo.chip == SIS_300) { inSISIDXREG(SISSR,0x3b,myflag); if(!(myflag & 0x01)) { @@ -2968,10 +2877,6 @@ } } - if(ivideo.vbflags & (VB_301C|VB_302ELV)) { - orSISIDXREG(SISPART4,0x0d,0x04); - } - haveresult = 0; for(j = 0; j < 10; j++) { result = 0; @@ -3014,11 +2919,9 @@ outSISIDXREG(SISPART4,0x0d,backupP4_0d); } -/* TW: Determine and detect attached TV's on Chrontel */ -void -SiS_SenseCh(void) +/* Determine and detect attached TV's on Chrontel */ +static void __devinit SiS_SenseCh(void) { - u8 temp1, temp2; #ifdef CONFIG_FB_SIS_300 unsigned char test[3]; @@ -3143,16 +3046,17 @@ /* ------------------------ Heap routines -------------------------- */ -static int sisfb_heap_init(void) +static int __devinit +sisfb_heap_init(void) { SIS_OH *poh; u8 temp=0; #ifdef CONFIG_FB_SIS_315 int agp_enabled = 1; u32 agp_size; - unsigned long *cmdq_baseport = 0; - unsigned long *read_port = 0; - unsigned long *write_port = 0; + unsigned long *cmdq_baseport = 0; + unsigned long *read_port = 0; + unsigned long *write_port = 0; SIS_CMDTYPE cmd_type; #ifndef AGPOFF #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) @@ -3162,7 +3066,7 @@ agp_kern_info *agp_info; agp_memory *agp; #endif - u32 agp_phys; + unsigned long agp_phys; #endif #endif /* The heap start is either set manually using the "mem" parameter, or @@ -3179,8 +3083,8 @@ * On the 315 and Xabre series, the default is a 1MB heap since DRI is not * supported there. */ - if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { - if(sisvga_engine == SIS_300_VGA) { + if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if (ivideo.video_size > 0x1000000) { ivideo.heapstart = 0xc00000; } else if (ivideo.video_size > 0x800000) { @@ -3194,8 +3098,7 @@ } else { ivideo.heapstart = sisfb_mem * 1024; } - sisfb_heap_start = - (unsigned long) (ivideo.video_vbase + ivideo.heapstart); + sisfb_heap_start = (unsigned long) (ivideo.video_vbase + ivideo.heapstart); printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", (int)(ivideo.heapstart / 1024)); @@ -3203,8 +3106,8 @@ sisfb_heap_size = sisfb_heap_end - sisfb_heap_start; #ifdef CONFIG_FB_SIS_315 - if (sisvga_engine == SIS_315_VGA) { - /* Now initialize the 310 series' command queue mode. + if(ivideo.sisvga_engine == SIS_315_VGA) { + /* Now initialize the 315/330 series' command queue mode. * On 315, there are three queue modes available which * are chosen by setting bits 7:5 in SR26: * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep @@ -3275,12 +3178,11 @@ agp_enabled = 0; #endif - /* TW: Now select the queue mode */ + /* Now select the queue mode */ - if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) { + if((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) { cmd_type = AGP_CMD_QUEUE; printk(KERN_INFO "sisfb: Using AGP queue mode\n"); -/* } else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */ } else if (sisfb_queuemode == VM_CMD_QUEUE) { cmd_type = VM_CMD_QUEUE; printk(KERN_INFO "sisfb: Using VRAM queue mode\n"); @@ -3326,7 +3228,7 @@ *cmdq_baseport = agp_phys; - sisfb_caps |= AGP_CMD_QUEUE_CAP; + ivideo.caps |= AGP_CMD_QUEUE_CAP; #endif break; @@ -3345,10 +3247,8 @@ *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; - sisfb_caps |= VM_CMD_QUEUE_CAP; + ivideo.caps |= VM_CMD_QUEUE_CAP; - DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n", - *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); break; default: /* MMIO */ @@ -3366,18 +3266,16 @@ *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; - sisfb_caps |= MMIO_CMD_QUEUE_CAP; + ivideo.caps |= MMIO_CMD_QUEUE_CAP; - DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n", - *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); break; } } /* sisvga_engine = 315 */ #endif #ifdef CONFIG_FB_SIS_300 - if (sisvga_engine == SIS_300_VGA) { - /* TW: Now initialize TurboQueue. TB is always located at the very + if(ivideo.sisvga_engine == SIS_300_VGA) { + /* Now initialize TurboQueue. TB is always located at the very * top of the video RAM. */ if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) { unsigned int tqueue_pos; @@ -3396,26 +3294,22 @@ outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp); - sisfb_caps |= TURBO_QUEUE_CAP; + ivideo.caps |= TURBO_QUEUE_CAP; sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE; - DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n", - sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024); + } } #endif - /* TW: Now reserve memory for the HWCursor. It is always located at the very - top of the videoRAM, right below the TB memory area (if used). */ - if (sisfb_heap_size >= sisfb_hwcursor_size) { - sisfb_heap_end -= sisfb_hwcursor_size; - sisfb_heap_size -= sisfb_hwcursor_size; - sisfb_hwcursor_vbase = sisfb_heap_end; + /* Now reserve memory for the HWCursor. It is always located at the very + top of the videoRAM, right below the TB memory area (if used). */ + if(sisfb_heap_size >= ivideo.hwcursor_size) { + sisfb_heap_end -= ivideo.hwcursor_size; + sisfb_heap_size -= ivideo.hwcursor_size; + ivideo.hwcursor_vbase = sisfb_heap_end; - sisfb_caps |= HW_CURSOR_CAP; - - DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n", - sisfb_heap_end, sisfb_hwcursor_size/1024); + ivideo.caps |= HW_CURSOR_CAP; } sisfb_heap.poha_chain = NULL; @@ -3449,14 +3343,15 @@ return 0; } -static SIS_OH *sisfb_poh_new_node(void) +static SIS_OH * +sisfb_poh_new_node(void) { int i; unsigned long cOhs; SIS_OHALLOC *poha; SIS_OH *poh; - if (sisfb_heap.poh_freelist == NULL) { + if(sisfb_heap.poh_freelist == NULL) { poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL); if(!poha) return NULL; @@ -3466,7 +3361,7 @@ cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1; poh = &poha->aoh[0]; - for (i = cOhs - 1; i != 0; i--) { + for(i = cOhs - 1; i != 0; i--) { poh->poh_next = poh + 1; poh = poh + 1; } @@ -3481,13 +3376,14 @@ return (poh); } -static SIS_OH *sisfb_poh_allocate(unsigned long size) +static SIS_OH * +sisfb_poh_allocate(unsigned long size) { SIS_OH *pohThis; SIS_OH *pohRoot; int bAllocated = 0; - if (size > sisfb_heap.max_freesize) { + if(size > sisfb_heap.max_freesize) { DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", (unsigned int) size / 1024); return (NULL); @@ -3495,7 +3391,7 @@ pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &sisfb_heap.oh_free) { + while(pohThis != &sisfb_heap.oh_free) { if (size <= pohThis->size) { bAllocated = 1; break; @@ -3503,19 +3399,19 @@ pohThis = pohThis->poh_next; } - if (!bAllocated) { + if(!bAllocated) { DPRINTK("sisfb: Can't allocate %dk size on offscreen\n", (unsigned int) size / 1024); return (NULL); } - if (size == pohThis->size) { + if(size == pohThis->size) { pohRoot = pohThis; sisfb_delete_node(pohThis); } else { pohRoot = sisfb_poh_new_node(); - if (pohRoot == NULL) { + if(pohRoot == NULL) { return (NULL); } @@ -3534,7 +3430,8 @@ return (pohRoot); } -static void sisfb_delete_node(SIS_OH *poh) +static void +sisfb_delete_node(SIS_OH *poh) { SIS_OH *poh_prev; SIS_OH *poh_next; @@ -3544,10 +3441,10 @@ poh_prev->poh_next = poh_next; poh_next->poh_prev = poh_prev; - } -static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) +static void +sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh) { SIS_OH *pohTemp; @@ -3560,7 +3457,8 @@ poh->poh_next = pohTemp; } -static SIS_OH *sisfb_poh_free(unsigned long base) +static SIS_OH * +sisfb_poh_free(unsigned long base) { SIS_OH *pohThis; SIS_OH *poh_freed; @@ -3581,7 +3479,7 @@ poh_freed = poh_freed->poh_next; } - if (!foundNode) return (NULL); + if(!foundNode) return(NULL); sisfb_heap.max_freesize += poh_freed->size; @@ -3591,12 +3489,11 @@ pohThis = sisfb_heap.oh_free.poh_next; - while (pohThis != &sisfb_heap.oh_free) { - if (pohThis->offset == ulUpper) { + while(pohThis != &sisfb_heap.oh_free) { + if(pohThis->offset == ulUpper) { poh_next = pohThis; } - else if ((pohThis->offset + pohThis->size) == - ulLower) { + else if((pohThis->offset + pohThis->size) == ulLower) { poh_prev = pohThis; } pohThis = pohThis->poh_next; @@ -3604,42 +3501,43 @@ sisfb_delete_node(poh_freed); - if (poh_prev && poh_next) { + if(poh_prev && poh_next) { poh_prev->size += (poh_freed->size + poh_next->size); sisfb_delete_node(poh_next); sisfb_free_node(poh_freed); sisfb_free_node(poh_next); - return (poh_prev); + return(poh_prev); } - if (poh_prev) { + if(poh_prev) { poh_prev->size += poh_freed->size; sisfb_free_node(poh_freed); - return (poh_prev); + return(poh_prev); } - if (poh_next) { + if(poh_next) { poh_next->size += poh_freed->size; poh_next->offset = poh_freed->offset; sisfb_free_node(poh_freed); - return (poh_next); + return(poh_next); } sisfb_insert_node(&sisfb_heap.oh_free, poh_freed); - return (poh_freed); + return(poh_freed); } -static void sisfb_free_node(SIS_OH *poh) +static void +sisfb_free_node(SIS_OH *poh) { if(poh == NULL) return; poh->poh_next = sisfb_heap.poh_freelist; sisfb_heap.poh_freelist = poh; - } -void sis_malloc(struct sis_memreq *req) +void +sis_malloc(struct sis_memreq *req) { SIS_OH *poh; @@ -3658,7 +3556,8 @@ } } -void sis_free(unsigned long base) +void +sis_free(unsigned long base) { SIS_OH *poh; @@ -3672,7 +3571,8 @@ /* --------------------- SetMode routines ------------------------- */ -static void sisfb_pre_setmode(void) +static void +sisfb_pre_setmode(void) { u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0; @@ -3682,7 +3582,7 @@ cr31 &= ~0x60; cr31 |= 0x04; - cr33 = sisfb_rate_idx & 0x0F; + cr33 = ivideo.rate_idx & 0x0F; SiS_SetEnableDstn(&SiS_Pr, FALSE); SiS_SetEnableFstn(&SiS_Pr, FALSE); @@ -3733,7 +3633,7 @@ if(sisfb_nocrt2rate) { cr33 |= (sisbios_mode[sisfb_mode_idx].rate_idx << 4); } else { - cr33 |= ((sisfb_rate_idx & 0x0F) << 4); + cr33 |= ((ivideo.rate_idx & 0x0F) << 4); } break; default: /* disable CRT2 */ @@ -3751,7 +3651,7 @@ outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33); #ifdef CONFIG_FB_SIS_315 - if(sisvga_engine == SIS_315_VGA) { + if(ivideo.sisvga_engine == SIS_315_VGA) { /* Clear LCDA and PAL-N/M bits */ andSISIDXREG(SISCR,0x38,~0x03); if(ivideo.chip < SIS_661) { @@ -3765,29 +3665,39 @@ SiS_Pr.SiS_UseOEM = sisfb_useoem; } -static void sisfb_post_setmode(void) +static void +sisfb_post_setmode(void) { u8 reg; BOOLEAN crt1isoff = FALSE; + BOOLEAN doit = TRUE; #ifdef CONFIG_FB_SIS_315 u8 reg1; #endif -#ifdef CONFIG_FB_SIS_300 - BOOLEAN doit = TRUE; -#endif + + /* Now we actually HAVE changed the display mode */ + ivideo.modechanged = 1; + /* We can't switch off CRT1 if bridge is in slave mode */ if(ivideo.vbflags & VB_VIDEOBRIDGE) { + inSISIDXREG(SISPART1, 0x00, reg); #ifdef CONFIG_FB_SIS_300 - if(sisvga_engine == SIS_300_VGA) { - inSISIDXREG(SISPART1, 0x00, reg); + if(ivideo.sisvga_engine == SIS_300_VGA) { if((reg & 0xa0) == 0x20) { doit = FALSE; } } #endif +#ifdef CONFIG_FB_SIS_315 + if(ivideo.sisvga_engine == SIS_315_VGA) { + if((reg & 0x50) == 0x10) { + doit = FALSE; + } + } +#endif } else sisfb_crt1off = 0; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { #ifdef CONFIG_FB_SIS_300 if((sisfb_crt1off) && (doit)) { @@ -3803,7 +3713,7 @@ } else { #ifdef CONFIG_FB_SIS_315 - if(sisfb_crt1off) { + if((sisfb_crt1off) && (doit)) { crt1isoff = TRUE; reg = 0x40; reg1 = 0xc0; @@ -3813,7 +3723,7 @@ reg1 = 0x00; } - setSISIDXREG(SISCR, 0x63, ~0x40, reg); + setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, ~0x40, reg); setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1); #endif @@ -3858,7 +3768,7 @@ break; } - orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01); + orSISIDXREG(SISPART1, ivideo.CRT2_write_enable, 0x01); if(ivideo.vbflags & TV_NTSC) { @@ -3931,13 +3841,7 @@ } } - if ((filter >= 0) && (filter <= 7)) { - DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, - sis_TV_filter[filter_tb].filter[filter][0], - sis_TV_filter[filter_tb].filter[filter][1], - sis_TV_filter[filter_tb].filter[filter][2], - sis_TV_filter[filter_tb].filter[filter][3] - ); + if((filter >= 0) && (filter <= 7)) { outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0])); outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1])); outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2])); @@ -3945,11 +3849,10 @@ } } - } #ifndef MODULE -int sisfb_setup(char *options) +int __init sisfb_setup(char *options) { char *this_opt; @@ -3960,76 +3863,85 @@ ivideo.refresh_rate = 0; SiS_Pr.SiS_CustomT = CUT_NONE; SiS_Pr.UsePanelScaler = -1; + SiS_Pr.CenterScreen = -1; SiS_Pr.LVDSHL = -1; +#if !defined(__i386__) && !defined(__x86_64__) + sisfb_resetcard = 0; + sisfb_videoram = 0; +#endif printk(KERN_DEBUG "sisfb: Options %s\n", options); - if (!options || !*options) + if(!options || !(*options)) return 0; while((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) continue; + if(!(*this_opt)) continue; - if (!strnicmp(this_opt, "mode:", 5)) { + if(!strnicmp(this_opt, "mode:", 5)) { sisfb_search_mode(this_opt + 5, FALSE); - } else if (!strnicmp(this_opt, "vesa:", 5)) { + } else if(!strnicmp(this_opt, "vesa:", 5)) { sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - } else if (!strnicmp(this_opt, "inverse", 7)) { + } else if(!strnicmp(this_opt, "inverse", 7)) { sisfb_inverse = 1; /* fb_invert_cmaps(); */ - } else if (!strnicmp(this_opt, "font:", 5)) { - strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1); - sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0'; + } else if(!strnicmp(this_opt, "font:", 5)) { + if(strlen(this_opt + 5) < 40) { + strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1); + sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0'; + } #endif - } else if (!strnicmp(this_opt, "vrate:", 6)) { + } else if(!strnicmp(this_opt, "vrate:", 6)) { ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0); sisfb_parm_rate = ivideo.refresh_rate; - } else if (!strnicmp(this_opt, "rate:", 5)) { + } else if(!strnicmp(this_opt, "rate:", 5)) { ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0); sisfb_parm_rate = ivideo.refresh_rate; - } else if (!strnicmp(this_opt, "off", 3)) { + } else if(!strnicmp(this_opt, "off", 3)) { sisfb_off = 1; - } else if (!strnicmp(this_opt, "crt1off", 7)) { + } else if(!strnicmp(this_opt, "crt1off", 7)) { sisfb_crt1off = 1; - } else if (!strnicmp(this_opt, "filter:", 7)) { + } else if(!strnicmp(this_opt, "filter:", 7)) { filter = (int)simple_strtoul(this_opt + 7, NULL, 0); - } else if (!strnicmp(this_opt, "forcecrt2type:", 14)) { + } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) { sisfb_search_crt2type(this_opt + 14); - } else if (!strnicmp(this_opt, "forcecrt1:", 10)) { + } else if(!strnicmp(this_opt, "forcecrt1:", 10)) { sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0); - } else if (!strnicmp(this_opt, "tvmode:",7)) { + } else if(!strnicmp(this_opt, "tvmode:",7)) { sisfb_search_tvstd(this_opt + 7); - } else if (!strnicmp(this_opt, "tvstandard:",11)) { + } else if(!strnicmp(this_opt, "tvstandard:",11)) { sisfb_search_tvstd(this_opt + 7); - } else if (!strnicmp(this_opt, "mem:",4)) { + } else if(!strnicmp(this_opt, "mem:",4)) { sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0); - } else if (!strnicmp(this_opt, "queuemode:", 10)) { + } else if(!strnicmp(this_opt, "queuemode:", 10)) { sisfb_search_queuemode(this_opt + 10); - } else if (!strnicmp(this_opt, "pdc:", 4)) { + } else if(!strnicmp(this_opt, "pdc:", 4)) { sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0); - } else if (!strnicmp(this_opt, "noaccel", 7)) { + } else if(!strnicmp(this_opt, "pdc1:", 5)) { + sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0); + } else if(!strnicmp(this_opt, "noaccel", 7)) { sisfb_accel = 0; - } else if (!strnicmp(this_opt, "noypan", 6)) { + } else if(!strnicmp(this_opt, "noypan", 6)) { sisfb_ypan = 0; - } else if (!strnicmp(this_opt, "nomax", 5)) { + } else if(!strnicmp(this_opt, "nomax", 5)) { sisfb_max = 0; - } else if (!strnicmp(this_opt, "userom:", 7)) { + } else if(!strnicmp(this_opt, "userom:", 7)) { sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0); - } else if (!strnicmp(this_opt, "useoem:", 7)) { + } else if(!strnicmp(this_opt, "useoem:", 7)) { sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0); - } else if (!strnicmp(this_opt, "nocrt2rate", 10)) { + } else if(!strnicmp(this_opt, "nocrt2rate", 10)) { sisfb_nocrt2rate = 1; - } else if (!strnicmp(this_opt, "scalelcd:", 9)) { + } else if(!strnicmp(this_opt, "scalelcd:", 9)) { unsigned long temp = 2; temp = simple_strtoul(this_opt + 9, NULL, 0); if((temp == 0) || (temp == 1)) { SiS_Pr.UsePanelScaler = temp ^ 1; } - } else if (!strnicmp(this_opt, "specialtiming:", 14)) { + } else if(!strnicmp(this_opt, "specialtiming:", 14)) { sisfb_search_specialtiming(this_opt + 14); - } else if (!strnicmp(this_opt, "lvdshl:", 7)) { + } else if(!strnicmp(this_opt, "lvdshl:", 7)) { unsigned long temp = 4; temp = simple_strtoul(this_opt + 7, NULL, 0); if((temp >= 0) && (temp <= 3)) { @@ -4037,11 +3949,17 @@ } } else if(this_opt[0] >= '0' && this_opt[0] <= '9') { sisfb_search_mode(this_opt, TRUE); +#if !defined(__i386__) && !defined(__x86_64__) + } else if(!strnicmp(this_opt, "resetcard", 9)) { + sisfb_resetcard = 1; + } else if(!strnicmp(this_opt, "videoram:", 9)) { + sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0); +#endif } else { printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt); } - /* TW: Acceleration only with MMIO mode */ + /* Acceleration only with MMIO mode */ if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) { sisfb_accel = 0; } @@ -4051,177 +3969,448 @@ } #endif -static char *sis_find_rom(void) +static char * __devinit sis_find_rom(struct pci_dev *pdev) { -#if defined(__i386__) +#if defined(__i386__) || defined(__x86_64__) u32 segstart; - unsigned char *rom_base; - unsigned char *rom; - int stage; - int i; - char sis_rom_sig[] = "Silicon Integrated Systems"; - char *sis_sig_300[4] = { - "300", "540", "630", "730" - }; - char *sis_sig_310[11] = { - "315", "315", "315", "5315", "6325", "6325", - "Xabre", "6330", "6330", "6330", "6330" - }; - ushort sis_nums_300[4] = { - SIS_300, SIS_540, SIS_630, SIS_730 - }; - unsigned short sis_nums_310[11] = { - SIS_315PRO, SIS_315H, SIS_315, SIS_550, SIS_650, SIS_740, - SIS_330, SIS_661, SIS_741, SIS_660, SIS_760 - }; + unsigned char *rom_base, *rom; + int romptr; + unsigned short pciid; for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { - stage = 1; + rom_base = (unsigned char *)ioremap(segstart, 0x10000); + if(!rom_base) continue; - rom_base = (char *)ioremap(segstart, 0x1000); + if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) { + iounmap(rom_base); + continue; + } - if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) - stage = 2; + romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr > (0x10000 - 8)) { + iounmap(rom_base); + continue; + } - if (stage != 2) { - iounmap(rom_base); - continue; - } + rom = rom_base + romptr; + if((readb(rom) != 'P') || (readb(rom + 1) != 'C') || + (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) { + iounmap(rom_base); + continue; + } - rom = rom_base + (unsigned short)(*(rom_base + 0x12) | (*(rom_base + 0x13) << 8)); - if(strncmp(sis_rom_sig, rom, strlen(sis_rom_sig)) == 0) { - stage = 3; - } - if(stage != 3) { - iounmap(rom_base); - continue; - } - - rom = rom_base + (unsigned short)(*(rom_base + 0x14) | (*(rom_base + 0x15) << 8)); - for(i = 0;(i < 4) && (stage != 4); i++) { - if(strncmp(sis_sig_300[i], rom, strlen(sis_sig_300[i])) == 0) { - if(sis_nums_300[i] == ivideo.chip) { - stage = 4; - break; - } - } - } - if(stage != 4) { - for(i = 0;(i < 11) && (stage != 4); i++) { - if(strncmp(sis_sig_310[i], rom, strlen(sis_sig_310[i])) == 0) { - if(sis_nums_310[i] == ivideo.chip) { - stage = 4; - break; - } - } - } + pciid = readb(rom + 4) | (readb(rom + 5) << 8); + if(pciid != 0x1039) { + iounmap(rom_base); + continue; } - if(stage != 4) { - iounmap(rom_base); - continue; - } + pciid = readb(rom + 6) | (readb(rom + 7) << 8); + if(pciid == ivideo.chip_id) return rom_base; - return rom_base; + iounmap(rom_base); } +#else + unsigned char *rom_base, *rom, *myrombase = NULL; + int romptr; + unsigned short pciid; + u32 backup; + + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, + (ivideo.video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE); + + rom_base = ioremap(ivideo.video_base, 65536); + if(rom_base) { + if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) { + romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8)); + if(romptr <= (0x10000 - 8)) { + rom = rom_base + romptr; + if((readb(rom) == 'P') && (readb(rom + 1) == 'C') && + (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) { + pciid = readb(rom + 4) | (readb(rom + 5) << 8); + if(pciid == 0x1039) { + pciid = readb(rom + 6) | (readb(rom + 7) << 8); + if(pciid == ivideo.chip_id) { + if((myrombase = vmalloc(65536))) { + memcpy_fromio(myrombase, rom_base, 65536); + } + } + } + } + } + } + iounmap(rom_base); + } + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup); + if(myrombase) return myrombase; #endif return NULL; } +#ifdef SIS300 +static int __devinit +sisfb_chkbuswidth300(ULONG FBAddress) +{ + int i, j; + USHORT temp; + UCHAR reg; + + andSISIDXREG(SISSR,0x15,0xFB); + orSISIDXREG(SISSR,0x15,0x04); + outSISIDXREG(SISSR,0x13,0x00); + outSISIDXREG(SISSR,0x14,0xBF); + + for(i=0; i<2; i++) { + temp = 0x1234; + for(j=0; j<4; j++) { + writew(temp, FBAddress); + if(readw(FBAddress) == temp) break; + orSISIDXREG(SISSR,0x3c,0x01); + inSISIDXREG(SISSR,0x05,reg); + inSISIDXREG(SISSR,0x05,reg); + andSISIDXREG(SISSR,0x3c,0xfe); + inSISIDXREG(SISSR,0x05,reg); + inSISIDXREG(SISSR,0x05,reg); + temp++; + } + } + writel(0x01234567L, FBAddress); + writel(0x456789ABL, (FBAddress+4)); + writel(0x89ABCDEFL, (FBAddress+8)); + writel(0xCDEF0123L, (FBAddress+12)); + inSISIDXREG(SISSR,0x3b,reg); + if(reg & 0x01) { + if(readl((FBAddress+12)) == 0xCDEF0123L) return(4); /* Channel A 128bit */ + } + if(readl((FBAddress+4)) == 0x456789ABL) return(2); /* Channel B 64bit */ + return(1); /* 32bit */ +} + +static void __devinit +sisfb_setramsize300(void) +{ + ULONG FBAddr = (ULONG)sishw_ext.pjVideoMemoryAddress, Addr; + USHORT SR13, SR14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0; + int PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount; + int RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank; + int PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k; + const USHORT SiS_DRAMType[17][5] = { + {0x0C,0x0A,0x02,0x40,0x39}, + {0x0D,0x0A,0x01,0x40,0x48}, + {0x0C,0x09,0x02,0x20,0x35}, + {0x0D,0x09,0x01,0x20,0x44}, + {0x0C,0x08,0x02,0x10,0x31}, + {0x0D,0x08,0x01,0x10,0x40}, + {0x0C,0x0A,0x01,0x20,0x34}, + {0x0C,0x09,0x01,0x08,0x32}, + {0x0B,0x08,0x02,0x08,0x21}, + {0x0C,0x08,0x01,0x08,0x30}, + {0x0A,0x08,0x02,0x04,0x11}, + {0x0B,0x0A,0x01,0x10,0x28}, + {0x09,0x08,0x02,0x02,0x01}, + {0x0B,0x09,0x01,0x08,0x24}, + {0x0B,0x08,0x01,0x04,0x20}, + {0x0A,0x08,0x01,0x02,0x10}, + {0x09,0x08,0x01,0x01,0x00} + }; + + buswidth = sisfb_chkbuswidth300(FBAddr); + + MB2Bank = 16; + Done = 0; + for(i = 6; i >= 0; i--) { + if(Done) break; + PseudoRankCapacity = 1 << i; + for(j = 4; j >= 1; j--) { + if(Done) break; + PseudoTotalCapacity = PseudoRankCapacity * j; + PseudoAdrPinCount = 15 - j; + if(PseudoTotalCapacity <= 64) { + for(k = 0; k <= 16; k++) { + if(Done) break; + RankCapacity = buswidth * SiS_DRAMType[k][3]; + AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0]; + if(RankCapacity == PseudoRankCapacity) + if(AdrPinCount <= PseudoAdrPinCount) { + if(j == 3) { /* Rank No */ + BankNumHigh = RankCapacity * MB2Bank * 3 - 1; + BankNumMid = RankCapacity * MB2Bank * 1 - 1; + } else { + BankNumHigh = RankCapacity * MB2Bank * j - 1; + BankNumMid = RankCapacity * MB2Bank * j / 2 - 1; + } + PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4; + PhysicalAdrHigh = BankNumHigh; + PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity; + PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh; + /* Write data */ + andSISIDXREG(SISSR,0x15,0xFB); /* Test */ + orSISIDXREG(SISSR,0x15,0x04); /* Test */ + TotalCapacity = SiS_DRAMType[k][3] * buswidth; + SR13 = SiS_DRAMType[k][4]; + if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80; + if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40; + if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00; + outSISIDXREG(SISSR,0x13,SR13); + outSISIDXREG(SISSR,0x14,SR14); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; + /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */ + writew(((USHORT)PhysicalAdrHigh), Addr); + Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh; + /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */ + writew(((USHORT)BankNumMid), Addr); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage; + /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */ + writew(((USHORT)PhysicalAdrHalfPage), Addr); + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage; + /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */ + writew(((USHORT)PhysicalAdrOtherPage), Addr); + /* Read data */ + Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh; + data = readw(Addr); /* *((USHORT *)(Addr)); */ + if(data == PhysicalAdrHigh) Done = 1; + } /* if */ + } /* for k */ + } /* if */ + } /* for j */ + } /* for i */ +} + +static void __devinit sisfb_post_sis300(void) +{ + u8 reg, v1, v2, v3, v4, v5, v6, v7, v8; + u16 index, rindex, memtype = 0; + + outSISIDXREG(SISSR,0x05,SIS_PASSWORD); + + if(sishw_ext.UseROM) { + if(sishw_ext.pjVirtualRomBase[0x52] & 0x80) { + memtype = sishw_ext.pjVirtualRomBase[0x52]; + } else { + inSISIDXREG(SISSR,0x3a,memtype); + } + memtype &= 0x07; + } -int __init sisfb_init(void) + if(ivideo.revision_id <= 0x13) { + v1 = 0x44; v2 = 0x42; v3 = 0x80; + v4 = 0x44; v5 = 0x42; v6 = 0x80; + } else { + v1 = 0x68; v2 = 0x43; v3 = 0x80; /* Assume 125Mhz MCLK */ + v4 = 0x68; v5 = 0x43; v6 = 0x80; /* Assume 125Mhz ECLK */ + if(sishw_ext.UseROM) { + index = memtype * 5; + rindex = index + 0x54; + v1 = sishw_ext.pjVirtualRomBase[rindex++]; + v2 = sishw_ext.pjVirtualRomBase[rindex++]; + v3 = sishw_ext.pjVirtualRomBase[rindex++]; + rindex = index + 0x7c; + v4 = sishw_ext.pjVirtualRomBase[rindex++]; + v5 = sishw_ext.pjVirtualRomBase[rindex++]; + v6 = sishw_ext.pjVirtualRomBase[rindex++]; + } + } + outSISIDXREG(SISSR,0x28,v1); + outSISIDXREG(SISSR,0x29,v2); + outSISIDXREG(SISSR,0x2a,v3); + outSISIDXREG(SISSR,0x2e,v4); + outSISIDXREG(SISSR,0x2f,v5); + outSISIDXREG(SISSR,0x30,v6); + v1 = 0x10; + if(sishw_ext.UseROM) v1 = sishw_ext.pjVirtualRomBase[0xa4]; + outSISIDXREG(SISSR,0x07,v1); /* DAC speed */ + outSISIDXREG(SISSR,0x11,0x0f); /* DDC, power save */ + v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a; + v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00; + if(sishw_ext.UseROM) { + memtype += 0xa5; + v1 = sishw_ext.pjVirtualRomBase[memtype]; + v2 = sishw_ext.pjVirtualRomBase[memtype + 8]; + v3 = sishw_ext.pjVirtualRomBase[memtype + 16]; + v4 = sishw_ext.pjVirtualRomBase[memtype + 24]; + v5 = sishw_ext.pjVirtualRomBase[memtype + 32]; + v6 = sishw_ext.pjVirtualRomBase[memtype + 40]; + v7 = sishw_ext.pjVirtualRomBase[memtype + 48]; + v8 = sishw_ext.pjVirtualRomBase[memtype + 56]; + } + if(ivideo.revision_id >= 0x80) v3 &= 0xfd; + outSISIDXREG(SISSR,0x15,v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */ + outSISIDXREG(SISSR,0x16,v2); + outSISIDXREG(SISSR,0x17,v3); + outSISIDXREG(SISSR,0x18,v4); + outSISIDXREG(SISSR,0x19,v5); + outSISIDXREG(SISSR,0x1a,v6); + outSISIDXREG(SISSR,0x1b,v7); + outSISIDXREG(SISSR,0x1c,v8); /* ---- */ + andSISIDXREG(SISSR,0x15,0xfb); + orSISIDXREG(SISSR,0x15,0x04); + if(sishw_ext.UseROM) { + if(sishw_ext.pjVirtualRomBase[0x53] & 0x02) { + orSISIDXREG(SISSR,0x19,0x20); + } + } + v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */ + if(ivideo.revision_id >= 0x80) v1 |= 0x01; + outSISIDXREG(SISSR,0x1f,v1); + outSISIDXREG(SISSR,0x20,0xa0); /* linear & relocated io */ + v1 = 0xf6; v2 = 0x0d; v3 = 0x00; + if(sishw_ext.UseROM) { + v1 = sishw_ext.pjVirtualRomBase[0xe8]; + v2 = sishw_ext.pjVirtualRomBase[0xe9]; + v3 = sishw_ext.pjVirtualRomBase[0xea]; + } + outSISIDXREG(SISSR,0x23,v1); + outSISIDXREG(SISSR,0x24,v2); + outSISIDXREG(SISSR,0x25,v3); + outSISIDXREG(SISSR,0x21,0x84); + outSISIDXREG(SISSR,0x22,0x00); + outSISIDXREG(SISCR,0x37,0x00); + orSISIDXREG(SISPART1,0x24,0x01); /* unlock crt2 */ + outSISIDXREG(SISPART1,0x00,0x00); + v1 = 0x40; v2 = 0x11; + if(sishw_ext.UseROM) { + v1 = sishw_ext.pjVirtualRomBase[0xec]; + v2 = sishw_ext.pjVirtualRomBase[0xeb]; + } + outSISIDXREG(SISPART1,0x02,v1); + if(ivideo.revision_id >= 0x80) v2 &= ~0x01; + inSISIDXREG(SISPART4,0x00,reg); + if((reg == 1) || (reg == 2)) { + outSISIDXREG(SISCR,0x37,0x02); + outSISIDXREG(SISPART2,0x00,0x1c); + v4 = 0x00; v5 = 0x00; v6 = 0x10; + if(sishw_ext.UseROM) { + v4 = sishw_ext.pjVirtualRomBase[0xf5]; + v5 = sishw_ext.pjVirtualRomBase[0xf6]; + v6 = sishw_ext.pjVirtualRomBase[0xf7]; + } + outSISIDXREG(SISPART4,0x0d,v4); + outSISIDXREG(SISPART4,0x0e,v5); + outSISIDXREG(SISPART4,0x10,v6); + outSISIDXREG(SISPART4,0x0f,0x3f); + inSISIDXREG(SISPART4,0x01,reg); + if(reg >= 0xb0) { + inSISIDXREG(SISPART4,0x23,reg); + reg &= 0x20; + reg <<= 1; + outSISIDXREG(SISPART4,0x23,reg); + } + } else { + v2 &= ~0x10; + } + outSISIDXREG(SISSR,0x32,v2); + andSISIDXREG(SISPART1,0x24,0xfe); /* Lock CRT2 */ + inSISIDXREG(SISSR,0x16,reg); + reg &= 0xc3; + outSISIDXREG(SISCR,0x35,reg); + outSISIDXREG(SISCR,0x83,0x00); +#if !defined(__i386__) && !defined(__x86_64__) + if(sisfb_videoram) { + outSISIDXREG(SISSR,0x13,0x28); /* ? */ + reg = ((sisfb_videoram >> 10) - 1) | 0x40; + outSISIDXREG(SISSR,0x14,reg); + } else { +#endif + /* Need to map max FB size for finding out about RAM size */ + sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x4000000); + if(sishw_ext.pjVideoMemoryAddress) { + sisfb_setramsize300(); + iounmap(sishw_ext.pjVideoMemoryAddress); + } else { + printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n"); + outSISIDXREG(SISSR,0x13,0x28); /* ? */ + outSISIDXREG(SISSR,0x14,0x47); /* 8MB, 64bit default */ + } +#if !defined(__i386__) && !defined(__x86_64__) + } +#endif + if(sishw_ext.UseROM) { + v1 = sishw_ext.pjVirtualRomBase[0xe6]; + v2 = sishw_ext.pjVirtualRomBase[0xe7]; + } else { + inSISIDXREG(SISSR,0x3a,reg); + if((reg & 0x30) == 0x30) { + v1 = 0x04; /* PCI */ + v2 = 0x92; + } else { + v1 = 0x14; /* AGP */ + v2 = 0xb2; + } + } + outSISIDXREG(SISSR,0x21,v1); + outSISIDXREG(SISSR,0x22,v2); +} +#endif + + +int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct pci_dev *pdev = NULL; - struct board *b; - int pdev_valid = 0; + struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data]; u32 reg32; u16 reg16; u8 reg; + int sisvga_enabled = 0; -#if 0 - /* for DOC VB */ - sisfb_set_reg4(0xcf8,0x800000e0); - reg32 = sisfb_get_reg3(0xcfc); - reg32 = reg32 | 0x00001000; - sisfb_set_reg4(0xcfc,reg32); - } -#endif - - if (sisfb_off) - return -ENXIO; + if(sisfb_off) return -ENXIO; - sisfb_registered = 0; sisfb_thismonitor.datavalid = FALSE; memset(&sishw_ext, 0, sizeof(sishw_ext)); + + memset(&ivideo, 0, sizeof(ivideo)); + ivideo.detectedpdc = 0xff; + ivideo.detectedpdca = 0xff; + ivideo.detectedlcda = 0xff; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) memset(&sisfb_lastrates[0], 0, 128); #endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) memset(&sis_disp, 0, sizeof(sis_disp)); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74) - pci_for_each_dev(pdev) { -#else - while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) { -#endif - for (b = sisdev_list; b->vendor; b++) { - if ((b->vendor == pdev->vendor) - && (b->device == pdev->device)) { - pdev_valid = 1; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - sis_fb_info = framebuffer_alloc(0, &pdev->dev); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + sis_fb_info = framebuffer_alloc(0, &pdev->dev); #else - sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL); + sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL); #endif - if(!sis_fb_info) return -ENOMEM; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - memset(sis_fb_info, 0, sizeof(*sis_fb_info)); + if(!sis_fb_info) return -ENOMEM; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)) + memset(sis_fb_info, 0, sizeof(*sis_fb_info)); #endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) - strcpy(sis_fb_info->modename, b->name); -#else - strcpy(myid, b->name); -#endif - ivideo.chip_id = pdev->device; - pci_read_config_byte(pdev, PCI_REVISION_ID, - &ivideo.revision_id); - pci_read_config_word(pdev, PCI_COMMAND, ®16); - sishw_ext.jChipRevision = ivideo.revision_id; - sisvga_enabled = reg16 & 0x01; - ivideo.pcibus = pdev->bus->number; - ivideo.pcislot = PCI_SLOT(pdev->devfn); - ivideo.pcifunc = PCI_FUNC(pdev->devfn); - ivideo.subsysvendor = pdev->subsystem_vendor; - ivideo.subsysdevice = pdev->subsystem_device; - break; - } - } - if (pdev_valid) - break; - } +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) + strcpy(sis_fb_info->modename, chipinfo->chip_name); +#else + strcpy(myid, chipinfo->chip_name); +#endif - if (!pdev_valid) - return -ENODEV; + ivideo.chip_id = pdev->device; + pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo.revision_id); + sishw_ext.jChipRevision = ivideo.revision_id; + pci_read_config_word(pdev, PCI_COMMAND, ®16); + sisvga_enabled = reg16 & 0x01; + ivideo.pcibus = pdev->bus->number; + ivideo.pcislot = PCI_SLOT(pdev->devfn); + ivideo.pcifunc = PCI_FUNC(pdev->devfn); + ivideo.subsysvendor = pdev->subsystem_vendor; + ivideo.subsysdevice = pdev->subsystem_device; + + ivideo.chip = chipinfo->chip; + ivideo.sisvga_engine = chipinfo->vgaengine; + ivideo.hwcursor_size = chipinfo->hwcursor_size; + ivideo.CRT2_write_enable = chipinfo->CRT2_write_enable; - switch (ivideo.chip_id) { + /* Patch special cases */ + switch(ivideo.chip_id) { #ifdef CONFIG_FB_SIS_300 - case PCI_DEVICE_ID_SI_300: - ivideo.chip = SIS_300; - sisvga_engine = SIS_300_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2; /* New X driver uses 2 buffers */ - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300; - break; case PCI_DEVICE_ID_SI_630_VGA: { - ivideo.chip = SIS_630; sisfb_set_reg4(0xCF8, 0x80000000); reg32 = sisfb_get_reg3(0xCFC); if(reg32 == 0x07301039) { @@ -4232,46 +4421,12 @@ strcpy(myid, "SIS 730"); #endif } - sisvga_engine = SIS_300_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300; break; } - case PCI_DEVICE_ID_SI_540_VGA: - ivideo.chip = SIS_540; - sisvga_engine = SIS_300_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300; - break; #endif #ifdef CONFIG_FB_SIS_315 - case PCI_DEVICE_ID_SI_315H: - ivideo.chip = SIS_315H; - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; - break; - case PCI_DEVICE_ID_SI_315: - ivideo.chip = SIS_315; - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; - break; - case PCI_DEVICE_ID_SI_315PRO: - ivideo.chip = SIS_315PRO; - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; - break; - case PCI_DEVICE_ID_SI_550_VGA: - ivideo.chip = SIS_550; - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; - break; case PCI_DEVICE_ID_SI_650_VGA: { - ivideo.chip = SIS_650; sisfb_set_reg4(0xCF8, 0x80000000); reg32 = sisfb_get_reg3(0xCFC); if(reg32 == 0x07401039) { @@ -4282,17 +4437,8 @@ strcpy(myid, "SIS 740"); #endif } - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; break; } - case PCI_DEVICE_ID_SI_330: - ivideo.chip = SIS_330; - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; - break; case PCI_DEVICE_ID_SI_660_VGA: { sisfb_set_reg4(0xCF8, 0x80000000); @@ -4326,19 +4472,13 @@ strcpy(myid, "SIS 661"); #endif } - sisvga_engine = SIS_315_VGA; - sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2; - sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315; break; } #endif - default: - kfree(sis_fb_info); - return -ENODEV; } + sishw_ext.jChipType = ivideo.chip; - /* for Debug */ if( (sishw_ext.jChipType == SIS_315PRO) || (sishw_ext.jChipType == SIS_315) ) sishw_ext.jChipType = SIS_315H; @@ -4346,16 +4486,16 @@ ivideo.video_base = pci_resource_start(pdev, 0); ivideo.mmio_base = pci_resource_start(pdev, 1); sishw_ext.ulIOAddress = SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30; - ivideo.vga_base = (unsigned short) sishw_ext.ulIOAddress; + ivideo.vga_base = sishw_ext.ulIOAddress; - sisfb_mmio_size = pci_resource_len(pdev, 1); + ivideo.mmio_size = pci_resource_len(pdev, 1); if(!sisvga_enabled) { if(pci_enable_device(pdev)) { kfree(sis_fb_info); return -EIO; } - } + } SiS_Pr.SiS_Backup70xx = 0xff; SiS_Pr.SiS_CHOverScan = -1; @@ -4364,10 +4504,18 @@ SiS_Pr.HaveEMI = FALSE; SiS_Pr.HaveEMILCD = FALSE; SiS_Pr.OverruleEMI = FALSE; + SiS_Pr.SiS_SensibleSR11 = FALSE; + SiS_Pr.SiS_MyCR63 = 0x63; + SiS_Pr.PDC = -1; + SiS_Pr.PDCA = -1; + if(ivideo.chip >= SIS_661) { + SiS_Pr.SiS_SensibleSR11 = TRUE; + SiS_Pr.SiS_MyCR63 = 0x53; + } SiSRegInit(&SiS_Pr, sishw_ext.ulIOAddress); #ifdef CONFIG_FB_SIS_300 - /* TW: Find PCI systems for Chrontel/GPIO communication setup */ + /* Find PCI systems for Chrontel/GPIO communication setup */ if(ivideo.chip == SIS_630) { int i=0; do { @@ -4385,9 +4533,21 @@ outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#ifdef MODULE + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + int i; + for(i = 0x30; i <= 0x3f; i++) { + outSISIDXREG(SISCR,i,0x00); + } + } + inSISIDXREG(SISCR,0x34,reg); + ivideo.modeprechange = ((reg & 0x7f)) ? (reg & 0x7f) : 0x03; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#ifdef MODULE if((reg & 0x80) && (reg != 0xff)) { if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) { printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n"); @@ -4398,41 +4558,31 @@ #endif #endif - if (sisvga_engine == SIS_315_VGA) { - switch (ivideo.chip) { - case SIS_315H: - case SIS_315: - case SIS_330: - sishw_ext.bIntegratedMMEnabled = TRUE; - break; - case SIS_550: - case SIS_650: - case SIS_740: - case SIS_661: - case SIS_741: - case SIS_660: - case SIS_760: - sishw_ext.bIntegratedMMEnabled = TRUE; - break; - default: - break; - } - } else if (sisvga_engine == SIS_300_VGA) { - if (ivideo.chip == SIS_300) { + if(ivideo.sisvga_engine == SIS_315_VGA) { + sishw_ext.bIntegratedMMEnabled = TRUE; + } else if(ivideo.sisvga_engine == SIS_300_VGA) { + if(ivideo.chip == SIS_300) { sishw_ext.bIntegratedMMEnabled = TRUE; } else { inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg); - if (reg & SIS_SCRATCH_REG_1A_MASK) + if(reg & SIS_SCRATCH_REG_1A_MASK) sishw_ext.bIntegratedMMEnabled = TRUE; else sishw_ext.bIntegratedMMEnabled = FALSE; } } + ivideo.bios_vbase = ivideo.bios_abase = NULL; if(sisfb_userom) { - sishw_ext.pjVirtualRomBase = sis_find_rom(); + sishw_ext.pjVirtualRomBase = sis_find_rom(pdev); +#if defined(__i386__) || defined(__x86_64__) + ivideo.bios_vbase = sishw_ext.pjVirtualRomBase; /* mapped */ +#else + ivideo.bios_abase = sishw_ext.pjVirtualRomBase; /* allocated */ +#endif if(sishw_ext.pjVirtualRomBase) { - printk(KERN_INFO "sisfb: Video ROM found and mapped to %p\n", + printk(KERN_INFO "sisfb: Video ROM found and %s to %p\n", + ivideo.bios_vbase ? "mapped" : "copied", sishw_ext.pjVirtualRomBase); sishw_ext.UseROM = TRUE; } else { @@ -4445,8 +4595,6 @@ printk(KERN_INFO "sisfb: Video ROM usage disabled\n"); } sishw_ext.bSkipDramSizing = 0; - sishw_ext.pQueryVGAConfigSpace = &sisfb_query_VGA_config_space; - sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space; /* Find systems for special custom timing */ if(SiS_Pr.SiS_CustomT == CUT_NONE) { @@ -4502,7 +4650,7 @@ #ifdef CONFIG_FB_SIS_300 /* Mode numbers for 1280x768 are different for 300 and 315 series */ - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55; sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a; sisbios_mode[MODEINDEX_1280x768+2].mode_no = 0x5b; @@ -4511,36 +4659,38 @@ #endif sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE); - if (sishw_ext.pSR == NULL) { + if(sishw_ext.pSR == NULL) { printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n"); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); kfree(sis_fb_info); return -ENODEV; } sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF; sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE); - if (sishw_ext.pCR == NULL) { - vfree(sishw_ext.pSR); + if(sishw_ext.pCR == NULL) { printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n"); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); + vfree(sishw_ext.pSR); kfree(sis_fb_info); return -ENODEV; } sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF; #ifdef CONFIG_FB_SIS_300 - if(sisvga_engine == SIS_300_VGA) { - if(!sisvga_enabled) { - /* Mapping Max FB Size for 300 Init */ - sishw_ext.pjVideoMemoryAddress - = ioremap(ivideo.video_base, 0x4000000); - if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { - outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); - } + if(ivideo.sisvga_engine == SIS_300_VGA) { + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + if(ivideo.chip == SIS_300) sisfb_post_sis300(); } if(sisfb_get_dram_size_300()) { - vfree(sishw_ext.pSR); - vfree(sishw_ext.pCR); printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n"); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); + vfree(sishw_ext.pSR); + vfree(sishw_ext.pCR); kfree(sis_fb_info); return -ENODEV; } @@ -4548,12 +4698,16 @@ #endif #ifdef CONFIG_FB_SIS_315 - if (sisvga_engine == SIS_315_VGA) { - if (!sisvga_enabled) { - /* Mapping Max FB Size for 315 Init */ - sishw_ext.pjVideoMemoryAddress - = ioremap(ivideo.video_base, 0x8000000); - if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { + if(ivideo.sisvga_engine == SIS_315_VGA) { + if( (!sisvga_enabled) +#if !defined(__i386__) && !defined(__x86_64__) + || (sisfb_resetcard) +#endif + ) { + if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { + /* TODO: POSTing 315/330 not supported yet */ + /* Mapping Max FB Size for 315 Init */ + sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x8000000); outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD); sishw_ext.bSkipDramSizing = TRUE; sishw_ext.pSR[0].jIdx = 0x13; @@ -4562,12 +4716,14 @@ inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal); inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal); sishw_ext.pSR[2].jVal = 0xFF; + iounmap(sishw_ext.pjVideoMemoryAddress); } } if(sisfb_get_dram_size_315()) { + printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n"); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); vfree(sishw_ext.pSR); vfree(sishw_ext.pCR); - printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n"); kfree(sis_fb_info); return -ENODEV; } @@ -4575,53 +4731,73 @@ #endif if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { - /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE)); - /* Enable 2D accelerator engine */ orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D); - } sishw_ext.ulVideoMemorySize = ivideo.video_size; - if(sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c; - if(sisfb_pdc) { - SiS_Pr.PDC = sisfb_pdc; - } else { - SiS_Pr.PDC = 0; + if(sisfb_pdc != 0xff) { + if(ivideo.sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c; + else sisfb_pdc &= 0x1f; + SiS_Pr.PDC = sisfb_pdc; + } + if(ivideo.sisvga_engine == SIS_315_VGA) { + if(sisfb_pdca != 0xff) SiS_Pr.PDCA = sisfb_pdca & 0x1f; } - if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) { + if(!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) { printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n"); printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n"); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); vfree(sishw_ext.pSR); vfree(sishw_ext.pCR); kfree(sis_fb_info); return -ENODEV; } - if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) { + if(!request_mem_region(ivideo.mmio_base, ivideo.mmio_size, "sisfb MMIO")) { printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n"); release_mem_region(ivideo.video_base, ivideo.video_size); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); vfree(sishw_ext.pSR); vfree(sishw_ext.pCR); kfree(sis_fb_info); return -ENODEV; } - ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = - ioremap(ivideo.video_base, ivideo.video_size); - ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size); + ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, ivideo.video_size); + if(!ivideo.video_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n"); + release_mem_region(ivideo.video_base, ivideo.video_size); + release_mem_region(ivideo.mmio_base, ivideo.mmio_size); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); + vfree(sishw_ext.pSR); + vfree(sishw_ext.pCR); + kfree(sis_fb_info); + return -ENODEV; + } + + ivideo.mmio_vbase = ioremap(ivideo.mmio_base, ivideo.mmio_size); + if(!ivideo.mmio_vbase) { + printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n"); + iounmap(ivideo.video_vbase); + release_mem_region(ivideo.video_base, ivideo.video_size); + release_mem_region(ivideo.mmio_base, ivideo.mmio_size); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); + vfree(sishw_ext.pSR); + vfree(sishw_ext.pCR); + kfree(sis_fb_info); + return -ENODEV; + } printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - ivideo.video_base, ivideo.video_vbase, - ivideo.video_size / 1024); + ivideo.video_base, ivideo.video_vbase, ivideo.video_size / 1024); printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n", - ivideo.mmio_base, ivideo.mmio_vbase, - sisfb_mmio_size / 1024); + ivideo.mmio_base, ivideo.mmio_vbase, ivideo.mmio_size / 1024); if(sisfb_heap_init()) { printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n"); @@ -4631,11 +4807,12 @@ ivideo.vbflags = 0; + ivideo.newrom = SiSDetermineROMLayout661(&SiS_Pr, &sishw_ext); + if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN; sishw_ext.Is301BDH = FALSE; - sishw_ext.usExternalChip = 0; sisfb_sense_crt1(); @@ -4645,7 +4822,7 @@ sisfb_detect_VB_connect(); } - ivideo.currentvbflags = ivideo.vbflags & VB_VIDEOBRIDGE; + ivideo.currentvbflags = ivideo.vbflags & (VB_VIDEOBRIDGE | TV_STANDARD); if(ivideo.vbflags & VB_VIDEOBRIDGE) { if(sisfb_crt2type != -1) { @@ -4658,7 +4835,7 @@ /* Chrontel 700x TV detection often unreliable, therefore use a * different default order on such machines */ - if((sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & VB_CHRONTEL)) { + if((ivideo.sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & VB_CHRONTEL)) { if(ivideo.vbflags & CRT2_LCD) ivideo.currentvbflags |= CRT2_LCD; else if(ivideo.vbflags & CRT2_TV) ivideo.currentvbflags |= CRT2_TV; else if(ivideo.vbflags & CRT2_VGA) ivideo.currentvbflags |= CRT2_VGA; @@ -4673,67 +4850,99 @@ if(ivideo.vbflags & CRT2_LCD) { inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg); reg &= 0x0f; - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { sishw_ext.ulCRT2LCDType = sis300paneltype[reg]; + } else if(ivideo.chip >= SIS_661) { + sishw_ext.ulCRT2LCDType = sis661paneltype[reg]; } else { sishw_ext.ulCRT2LCDType = sis310paneltype[reg]; } } - - sisfb_detectedpdc = 0; - + #ifdef CONFIG_FB_SIS_300 /* Save the current PanelDelayCompensation if the LCD is currently used */ - if(sisvga_engine == SIS_300_VGA) { + if(ivideo.sisvga_engine == SIS_300_VGA) { if(ivideo.vbflags & (VB_LVDS | VB_30xBDH)) { int tmp; inSISIDXREG(SISCR,0x30,tmp); if(tmp & 0x20) { /* Currently on LCD? If yes, read current pdc */ - inSISIDXREG(SISPART1,0x13,sisfb_detectedpdc); - sisfb_detectedpdc &= 0x3c; - if(SiS_Pr.PDC == 0) { + inSISIDXREG(SISPART1,0x13,ivideo.detectedpdc); + ivideo.detectedpdc &= 0x3c; + if(SiS_Pr.PDC == -1) { /* Let option override detection */ - SiS_Pr.PDC = sisfb_detectedpdc; + SiS_Pr.PDC = ivideo.detectedpdc; } - printk(KERN_INFO - "sisfb: Detected LCD PanelDelayCompensation %d\n", - sisfb_detectedpdc); + printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n", + ivideo.detectedpdc); } - if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) { - printk(KERN_INFO - "sisfb: Using LCD PanelDelayCompensation %d\n", + if((SiS_Pr.PDC != -1) && (SiS_Pr.PDC != ivideo.detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n", SiS_Pr.PDC); } } } #endif - sisfb_detectedlcda = 0xff; - #ifdef CONFIG_FB_SIS_315 + if(ivideo.sisvga_engine == SIS_315_VGA) { + + /* Try to find about LCDA */ + if(ivideo.vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) { + int tmp; + inSISIDXREG(SISPART1,0x13,tmp); + if(tmp & 0x04) { + SiS_Pr.SiS_UseLCDA = TRUE; + ivideo.detectedlcda = 0x03; + printk(KERN_DEBUG + "sisfb: BIOS uses LCDA for low resolution and text modes\n"); + } + } - if(sisvga_engine == SIS_315_VGA) { /* Save PDC */ if(ivideo.vbflags & (VB_301LV | VB_302LV | VB_302ELV)) { int tmp; inSISIDXREG(SISCR,0x30,tmp); - if(tmp & 0x20) { + if((tmp & 0x20) || (ivideo.detectedlcda != 0xff)) { /* Currently on LCD? If yes, read current pdc */ - inSISIDXREG(SISPART1,0x2D,sisfb_detectedpdc); - if(SiS_Pr.PDC == 0) { - /* Let option override detection */ - SiS_Pr.PDC = sisfb_detectedpdc; + u8 pdc; + inSISIDXREG(SISPART1,0x2D,pdc); + ivideo.detectedpdc = (pdc & 0x0f) << 1; + ivideo.detectedpdca = (pdc & 0xf0) >> 3; + inSISIDXREG(SISPART1,0x35,pdc); + ivideo.detectedpdc |= ((pdc >> 7) & 0x01); + inSISIDXREG(SISPART1,0x20,pdc); + ivideo.detectedpdca |= ((pdc >> 6) & 0x01); + if(ivideo.newrom) { + /* New ROM invalidates other PDC resp. */ + if(ivideo.detectedlcda != 0xff) { + ivideo.detectedpdc = 0xff; + } else { + ivideo.detectedpdca = 0xff; + } + } + if(SiS_Pr.PDC == -1) { + if(ivideo.detectedpdc != 0xff) { + SiS_Pr.PDC = ivideo.detectedpdc; + } + } + if(SiS_Pr.PDCA == -1) { + if(ivideo.detectedpdca != 0xff) { + SiS_Pr.PDCA = ivideo.detectedpdca; + } + } + if(ivideo.detectedpdc != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n", + ivideo.detectedpdc); + } + if(ivideo.detectedpdca != 0xff) { + printk(KERN_INFO + "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n", + ivideo.detectedpdca); } - printk(KERN_INFO - "sisfb: Detected LCD PanelDelayCompensation %d\n", - sisfb_detectedpdc); - } - if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) { - printk(KERN_INFO - "sisfb: Using LCD PanelDelayCompensation %d\n", - SiS_Pr.PDC); } + /* Save EMI */ if(ivideo.vbflags & (VB_302LV | VB_302ELV)) { inSISIDXREG(SISPART4,0x30,SiS_Pr.EMI_30); @@ -4741,57 +4950,41 @@ inSISIDXREG(SISPART4,0x32,SiS_Pr.EMI_32); inSISIDXREG(SISPART4,0x33,SiS_Pr.EMI_33); SiS_Pr.HaveEMI = TRUE; - if(tmp & 0x20) SiS_Pr.HaveEMILCD = TRUE; + if((tmp & 0x20) || (ivideo.detectedlcda != 0xff)) { + SiS_Pr.HaveEMILCD = TRUE; + } } } - /* Try to find about LCDA */ - if(ivideo.vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) { - int tmp; - inSISIDXREG(SISCR,0x34,tmp); - if((tmp <= 0x13) || (tmp == 0xff)) { - /* Currently on LCDA? (Some BIOSes leave CR38) */ - inSISIDXREG(SISCR,0x38,tmp); - if((tmp & 0x03) == 0x03) SiS_Pr.SiS_UseLCDA = TRUE; - else { - /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */ - inSISIDXREG(SISCR,0x35,tmp); - if(tmp & 0x01) SiS_Pr.SiS_UseLCDA = TRUE; - else { - /* Currently on LCD? If so, we can find out - * by peeking the mode register - */ - inSISIDXREG(SISCR,0x30,tmp); - if(tmp & 0x20) { - inSISIDXREG(SISPART1,0x13,tmp); - if(tmp & 0x04) SiS_Pr.SiS_UseLCDA = TRUE; - } - } - } + /* Let user override detected PDCs (all bridges) */ + if(ivideo.vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) { + if((SiS_Pr.PDC != -1) && (SiS_Pr.PDC != ivideo.detectedpdc)) { + printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n", + SiS_Pr.PDC); } - if(SiS_Pr.SiS_UseLCDA) { - sisfb_detectedlcda = 0x03; - printk(KERN_DEBUG - "sisfb: Bridge uses LCDA for low resolution and text modes\n"); + if((SiS_Pr.PDCA != -1) && (SiS_Pr.PDCA != ivideo.detectedpdca)) { + printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n", + SiS_Pr.PDCA); } - } + } + } #endif - if (!sisfb_crt1off) { + if(!sisfb_crt1off) { sisfb_handle_ddc(&sisfb_thismonitor, 0); } else { - if ((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) && - (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) { + if((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) && + (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) { sisfb_handle_ddc(&sisfb_thismonitor, 1); } } - if (sisfb_mode_idx >= 0) + if(sisfb_mode_idx >= 0) sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags); - if (sisfb_mode_idx < 0) { - switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) { + if(sisfb_mode_idx < 0) { + switch(ivideo.currentvbflags & VB_DISPTYPE_DISP2) { case CRT2_LCD: sisfb_mode_idx = DEFAULT_LCDMODE; break; @@ -4804,19 +4997,19 @@ } } - sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no; + ivideo.mode_no = sisbios_mode[sisfb_mode_idx].mode_no; - if (ivideo.refresh_rate != 0) + if(ivideo.refresh_rate != 0) sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx); - if (sisfb_rate_idx == 0) { - sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; + if(ivideo.rate_idx == 0) { + ivideo.rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx; ivideo.refresh_rate = 60; } - if (sisfb_thismonitor.datavalid) { + if(sisfb_thismonitor.datavalid) { if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx, - sisfb_rate_idx, ivideo.refresh_rate)) { + ivideo.rate_idx, ivideo.refresh_rate)) { printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n"); } } @@ -4839,13 +5032,14 @@ sisfb_pre_setmode(); - if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) { + if(SiSSetMode(&SiS_Pr, &sishw_ext, ivideo.mode_no) == 0) { printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n", - sisfb_mode_no); + ivideo.mode_no); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); vfree(sishw_ext.pSR); vfree(sishw_ext.pCR); release_mem_region(ivideo.video_base, ivideo.video_size); - release_mem_region(ivideo.mmio_base, sisfb_mmio_size); + release_mem_region(ivideo.mmio_base, ivideo.mmio_size); kfree(sis_fb_info); return -EINVAL; } @@ -4877,7 +5071,7 @@ sisfb_set_disp(-1, &default_var, sis_fb_info); -#else /* --------- For 2.5: Setup a somewhat sane default var ------------ */ +#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */ printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n", ivideo.video_width, ivideo.video_height, ivideo.video_bpp, @@ -4891,10 +5085,10 @@ default_var.pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext, - sisfb_mode_no, sisfb_rate_idx)); + ivideo.mode_no, ivideo.rate_idx)); if(sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext, - sisfb_mode_no, sisfb_rate_idx, + ivideo.mode_no, ivideo.rate_idx, &default_var.left_margin, &default_var.right_margin, &default_var.upper_margin, &default_var.lower_margin, &default_var.hsync_len, &default_var.vsync_len, @@ -4927,23 +5121,24 @@ sis_fb_info->par = &ivideo; sis_fb_info->screen_base = ivideo.video_vbase; sis_fb_info->fbops = &sisfb_ops; +#ifdef NEWFBDEV sis_fb_info->class_dev.dev = &pdev->dev; +#endif sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info); sis_fb_info->pseudo_palette = pseudo_palette; fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0); #endif - printk(KERN_INFO "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags); + printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags); #ifdef CONFIG_MTRR ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base, (unsigned int) ivideo.video_size, MTRR_TYPE_WRCOMB, 1); if(ivideo.mtrr) { - printk(KERN_INFO "sisfb: Added MTRRs\n"); + printk(KERN_DEBUG "sisfb: Added MTRRs\n"); } - #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -4951,41 +5146,110 @@ #endif if(register_framebuffer(sis_fb_info) < 0) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if(ivideo.bios_abase) vfree(ivideo.bios_abase); vfree(sishw_ext.pSR); vfree(sishw_ext.pCR); release_mem_region(ivideo.video_base, ivideo.video_size); - release_mem_region(ivideo.mmio_base, sisfb_mmio_size); -#endif + release_mem_region(ivideo.mmio_base, ivideo.mmio_size); printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n"); kfree(sis_fb_info); return -EINVAL; } - sisfb_registered = 1; + ivideo.registered = 1; + + pci_set_drvdata(pdev, sis_fb_info); printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO); printk(KERN_DEBUG "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS); - + printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n", sisfb_accel ? "enabled" : "disabled", sisfb_ypan ? (sisfb_max ? "ypan (auto-max)" : "ypan (no auto-max)") : "redraw"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n", - GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename, VER_MAJOR, VER_MINOR, - VER_LEVEL); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename, #else - printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n", - sis_fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL); + sis_fb_info->node, myid, #endif + VER_MAJOR, VER_MINOR, VER_LEVEL); - printk(KERN_INFO "sisfb: (C) 2001-2003 Thomas Winischhofer.\n"); + printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n"); } /* if mode = "none" */ + return 0; } +/*****************************************************/ +/* PCI DEVICE HANDLING */ +/*****************************************************/ + +static void __devexit sisfb_remove(struct pci_dev *pdev) +{ + /* Unmap */ + iounmap(ivideo.video_vbase); + iounmap(ivideo.mmio_vbase); + if(ivideo.bios_vbase) iounmap(ivideo.bios_vbase); + + /* Release mem regions */ + release_mem_region(ivideo.video_base, ivideo.video_size); + release_mem_region(ivideo.mmio_base, ivideo.mmio_size); + +#ifdef CONFIG_MTRR + /* Release MTRR region */ + if(ivideo.mtrr) { + mtrr_del(ivideo.mtrr, + (unsigned int)ivideo.video_base, + (unsigned int)ivideo.video_size); + } +#endif + + /* Unregister the framebuffer */ + if(ivideo.registered) { + unregister_framebuffer(sis_fb_info); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3)) + framebuffer_release(sis_fb_info); +#else + kfree(sis_fb_info); +#endif + } + + if(sishw_ext.pSR) vfree(sishw_ext.pSR); + if(sishw_ext.pCR) vfree(sishw_ext.pCR); + if(ivideo.bios_abase) vfree(ivideo.bios_abase); + + pci_set_drvdata(pdev, NULL); + + /* TODO: Restore the initial mode + * This sounds easy but is as good as impossible + * on many machines with SiS chip and video bridge + * since text modes are always set up differently + * from machine to machine. Depends on the type + * of integration between chipset and bridge. + */ + if(ivideo.registered) { + printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n"); + } +}; + +static struct pci_driver sisfb_driver = { + .name = "sisfb", + .id_table = sisfb_pci_table, + .probe = sisfb_probe, + .remove = __devexit_p(sisfb_remove) +}; + +int __init sisfb_init(void) +{ + return(pci_module_init(&sisfb_driver)); +} + +/*****************************************************/ +/* MODULE */ +/*****************************************************/ #ifdef MODULE @@ -4997,7 +5261,8 @@ static char *forcecrt2type = NULL; static int forcecrt1 = -1; static char *queuemode = NULL; -static int pdc = 0; +static int pdc = -1; +static int pdc1 = -1; static int noaccel = -1; static int noypan = -1; static int nomax = -1; @@ -5011,10 +5276,14 @@ static int scalelcd = -1; static char *specialtiming = NULL; static int lvdshl = -1; +#if !defined(__i386__) && !defined(__x86_64__) +static int resetcard = 0; +static int videoram = 0; +#endif -MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/651/661/740/741/330/760 framebuffer driver"); +MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer driver"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Winischhofer ; SiS; Various others"); +MODULE_AUTHOR("Thomas Winischhofer ; SiS; Others"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MODULE_PARM(mode, "s"); @@ -5068,11 +5337,11 @@ MODULE_PARM(queuemode, "s"); MODULE_PARM_DESC(queuemode, - "\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP, VRAM,\n" - "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n" - "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n" - "require a totally different way of programming the engines. If any mode than\n" - "MMIO is selected, sisfb will disable its own 2D acceleration. On\n" + "\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP,\n" + "VRAM and MMIO. AGP is only available if the kernel has AGP support. The queue\n" + "mode is important to programs using the 2D/3D accelerator of the SiS chip.\n" + "The modes require a totally different way of programming the engines. If any\n" + "mode than MMIO is selected, sisfb will disable its own 2D acceleration. On\n" "300/540/630/730, this option is ignored. (default: MMIO)"); /* TW: "Import" the options from the X driver */ @@ -5083,16 +5352,16 @@ "on the amount of video RAM available. If 8MB of video RAM or less is available,\n" "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n" "otherwise at 12288KB. On 315 and Xabre series, the heap is 1MB by default. The\n" - "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n" - "XFree 4.x (x>=2)."); + "value is to be specified without 'KB' and should match the MaxXFBMem setting\n" + "for XFree 4.x (x>=2)."); MODULE_PARM(forcecrt2type, "s"); MODULE_PARM_DESC(forcecrt2type, "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n" "LCD, TV or secondary VGA. With this option, this autodetection can be\n" "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n" - "On systems with a 301(B/LV) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n" - "used instead of TV to override the TV detection. (default: [autodetected])"); + "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n" + "be used instead of TV to override the TV detection. (default: [autodetected])"); MODULE_PARM(forcecrt1, "i"); MODULE_PARM_DESC(forcecrt1, @@ -5105,9 +5374,14 @@ "\nThis is for manually selecting the LCD panel delay compensation. The driver\n" "should detect this correctly in most cases; however, sometimes this is not\n" "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n" - "on a 300 series chipset; 3 or 51 on a 315 series chipset. If the problem persists,\n" + "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n" "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n" - "and value from 0 to 255). (default: [autodetected])"); + "any value from 0 to 31). (default: autodetected, if LCD is active during start)"); + +MODULE_PARM(pdc1, "i"); +MODULE_PARM_DESC(pdc1, + "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315 series\n" + "only. (default: autodetected if LCD is in LCD-via-CRT1 mode during startup)"); MODULE_PARM(noaccel, "i"); MODULE_PARM_DESC(noaccel, @@ -5122,9 +5396,10 @@ MODULE_PARM(nomax, "i"); MODULE_PARM_DESC(nomax, "\nIf y-panning is enabled, sisfb will by default use the entire available video\n" - "memory for the virtual screen in order to optimize scrolling performance. If this\n" - "is set to anything other than 0, sisfb will not do this and thereby enable the user\n" - "to positively specify a virtual Y size of the screen using fbset. (default: 0)\n"); + "memory for the virtual screen in order to optimize scrolling performance. If\n" + "this is set to anything other than 0, sisfb will not do this and thereby \n" + "enable the user to positively specify a virtual Y size of the screen using\n" + "fbset. (default: 0)\n"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MODULE_PARM(inverse, "i"); @@ -5156,20 +5431,31 @@ MODULE_PARM(scalelcd, "i"); MODULE_PARM_DESC(scalelcd, "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n" - "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n" - "by itself, it will probably do this, otherwise you will see a black bar around\n" - "the screen image. Default: [autodetect if panel can scale]"); + "native resolution. Setting it to 0 will disable scaling; if the panel can\n" + "scale by itself, it will probably do this, otherwise you will see a black bar\n" + "around the screen image. Default: [autodetect if panel can scale]"); MODULE_PARM(specialtiming, "s"); MODULE_PARM(lvdshl, "i"); +#if !defined(__i386__) && !defined(__x86_64__) +MODULE_PARM(resetcard, "i"); +MODULE_PARM_DESC(resetcard, + "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n" + "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n" + "Default: 0"); +MODULE_PARM(videoram, "i"); +MODULE_PARM_DESC(videoram, + "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n" + "some non-x86 architectures where the memory auto detection fails. Only\n" + "relevant if resetcard is set, too. Default: [auto-detect]"); +#endif -int init_module(void) +int __init sisfb_init_module(void) { - int err; - SiS_Pr.UsePanelScaler = -1; + SiS_Pr.CenterScreen = -1; SiS_Pr.SiS_CustomT = CUT_NONE; SiS_Pr.LVDSHL = -1; @@ -5230,14 +5516,15 @@ sisfb_useoem = useoem; - if (queuemode) sisfb_search_queuemode(queuemode); - + if(queuemode) sisfb_search_queuemode(queuemode); + /* If other queuemode than MMIO, disable 2D accel and ypan */ if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) { sisfb_accel = 0; } - if(pdc) sisfb_pdc = pdc & 0x3c; + if(pdc != -1) sisfb_pdc = (pdc & 0x7f); + if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f); sisfb_nocrt2rate = nocrt2rate; @@ -5246,55 +5533,30 @@ if((lvdshl >= 0) && (lvdshl <= 3)) SiS_Pr.LVDSHL = lvdshl; - if((err = sisfb_init()) < 0) return err; - - return 0; -} - -void cleanup_module(void) -{ - /* Release mem regions */ - release_mem_region(ivideo.video_base, ivideo.video_size); - release_mem_region(ivideo.mmio_base, sisfb_mmio_size); +#if !defined(__i386__) && !defined(__x86_64__) + if(resetcard) sisfb_resetcard = 1; + else sisfb_resetcard = 0; -#ifdef CONFIG_MTRR - /* TW: Release MTRR region */ - if(ivideo.mtrr) { - mtrr_del(ivideo.mtrr, - (unsigned int)ivideo.video_base, - (unsigned int)ivideo.video_size); - } + if(videoram) sisfb_videoram = videoram; #endif - /* Unregister the framebuffer */ - if(sisfb_registered) { - unregister_framebuffer(sis_fb_info); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - framebuffer_release(sis_fb_info); -#else - kfree(sis_fb_info); -#endif - } + return(sisfb_init()); +} - if(sishw_ext.pSR) vfree(sishw_ext.pSR); - if(sishw_ext.pCR) vfree(sishw_ext.pCR); - - /* TODO: Restore the initial mode - * This sounds easy but is as good as impossible - * on many machines with SiS chip and video bridge - * since text modes are always set up differently - * from machine to machine. Depends on the type - * of integration between chipset and bridge. - */ - - printk(KERN_INFO "sisfb: Module unloaded\n"); +static void __exit sisfb_remove_module(void) +{ + pci_unregister_driver(&sisfb_driver); + printk(KERN_DEBUG "sisfb: Module unloaded\n"); } -#endif +module_init(sisfb_init_module); +module_exit(sisfb_remove_module); + +#endif /* /MODULE */ EXPORT_SYMBOL(sis_malloc); EXPORT_SYMBOL(sis_free); EXPORT_SYMBOL(sis_dispinfo); EXPORT_SYMBOL(ivideo); - + diff -urN linux-2.4.25/drivers/video/sis/sis_main.h linux-2.4.26/drivers/video/sis/sis_main.h --- linux-2.4.25/drivers/video/sis/sis_main.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/sis_main.h 2004-04-14 06:05:40.000000000 -0700 @@ -32,7 +32,7 @@ #define VER_MAJOR 1 #define VER_MINOR 6 -#define VER_LEVEL 25 +#define VER_LEVEL 32 #include "sis.h" @@ -161,12 +161,12 @@ #define MMIO_QUEUE_WRITEPORT 0x85C4 #define MMIO_QUEUE_READPORT 0x85C8 -#define IND_SIS_CRT2_WRITE_ENABLE_300 0x24 -#define IND_SIS_CRT2_WRITE_ENABLE_315 0x2F +#define SIS_CRT2_WENABLE_300 0x24 +#define SIS_CRT2_WENABLE_315 0x2F #define SIS_PASSWORD 0x86 /* SR05 */ #define SIS_INTERLACED_MODE 0x20 /* SR06 */ -#define SIS_8BPP_COLOR_MODE 0x0 +#define SIS_8BPP_COLOR_MODE 0x0 #define SIS_15BPP_COLOR_MODE 0x1 #define SIS_16BPP_COLOR_MODE 0x2 #define SIS_32BPP_COLOR_MODE 0x4 @@ -187,10 +187,10 @@ #define SIS315_DATA_BUS_64 0x00 #define SIS315_DATA_BUS_128 0x01 #define SIS315_DUAL_CHANNEL_MASK 0x0C -#define SIS315_SINGLE_CHANNEL_1_RANK 0x0 -#define SIS315_SINGLE_CHANNEL_2_RANK 0x1 +#define SIS315_SINGLE_CHANNEL_1_RANK 0x00 +#define SIS315_SINGLE_CHANNEL_2_RANK 0x01 #define SIS315_ASYM_DDR 0x02 -#define SIS315_DUAL_CHANNEL_1_RANK 0x3 +#define SIS315_DUAL_CHANNEL_1_RANK 0x03 #define SIS_SCRATCH_REG_1A_MASK 0x10 @@ -314,9 +314,40 @@ outSISIDXREG(base,idx,__Temp); \ } while (0) -/* ------------------- Global Variables ----------------------------- */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +/* Offscreen layout */ +typedef struct _SIS_GLYINFO { + unsigned char ch; + int fontwidth; + int fontheight; + u8 gmask[72]; + int ngmask; +} SIS_GLYINFO; + +static char sisfb_fontname[40]; +#endif -/* Fbcon variables */ +typedef struct _SIS_OH { + struct _SIS_OH *poh_next; + struct _SIS_OH *poh_prev; + unsigned long offset; + unsigned long size; +} SIS_OH; + +typedef struct _SIS_OHALLOC { + struct _SIS_OHALLOC *poha_next; + SIS_OH aoh[1]; +} SIS_OHALLOC; + +typedef struct _SIS_HEAP { + SIS_OH oh_free; + SIS_OH oh_used; + SIS_OH *poh_freelist; + SIS_OHALLOC *poha_chain; + unsigned long max_freesize; +} SIS_HEAP; + +/* Fbcon stuff */ static struct fb_info *sis_fb_info; static struct fb_var_screeninfo default_var = { @@ -384,38 +415,28 @@ static int currcon = 0; #endif -/* global flags */ static int sisfb_off = 0; static int sisfb_crt1off = 0; static int sisfb_forcecrt1 = -1; -static int sisvga_enabled = 0; +static int sisfb_crt2type = -1; /* CRT2 type (for overriding autodetection) */ +static int sisfb_tvplug = -1; /* Tv plug type (for overriding autodetection) */ static int sisfb_userom = 1; static int sisfb_useoem = -1; static int sisfb_parm_rate = -1; -static int sisfb_registered = 0; static int sisfb_mem = 0; -static int sisfb_pdc = 0; +static int sisfb_pdc = 0xff; +static int sisfb_pdca = 0xff; static int sisfb_ypan = -1; static int sisfb_max = -1; static int sisfb_nocrt2rate = 0; static int sisfb_dstn = 0; static int sisfb_fstn = 0; - -VGA_ENGINE sisvga_engine = UNKNOWN_VGA; int sisfb_accel = -1; - -/* These are to adapted according to VGA_ENGINE type */ -static int sisfb_hwcursor_size = 0; -static int sisfb_CRT2_write_enable = 0; - -int sisfb_crt2type = -1; /* CRT2 type (for overriding autodetection) */ -int sisfb_tvplug = -1; /* Tv plug type (for overriding autodetection) */ - -int sisfb_queuemode = -1; /* Use MMIO queue mode by default (315 series only) */ - -unsigned char sisfb_detectedpdc = 0; - -unsigned char sisfb_detectedlcda = 0xff; +int sisfb_queuemode = -1; /* Use MMIO queue mode by default (315 series only) */ +#if !defined(__i386__) && !defined(__x86_64__) +static int sisfb_resetcard = 0; +static int sisfb_videoram = 0; +#endif /* data for sis hardware ("par") */ struct video_info ivideo; @@ -429,10 +450,6 @@ /* SiS private structure */ SiS_Private SiS_Pr; -/* Card parameters */ -static unsigned long sisfb_mmio_size = 0; -static u8 sisfb_caps = 0; - typedef enum _SIS_CMDTYPE { MMIO_CMD = 0, AGP_CMD_QUEUE, @@ -440,22 +457,43 @@ } SIS_CMDTYPE; /* List of supported chips */ -static struct board { - u16 vendor, device; - const char *name; -} sisdev_list[] = { - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540 VGA"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630/730 VGA"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, "SIS 315H"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, "SIS 315"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, "SIS 315PRO"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 65x/M65x/740 VGA"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, "SIS 330"}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, "SIS 661FX/M661FX/741/760 VGA"}, - {0, 0, NULL} +static struct sisfb_chip_info { + int chip; + VGA_ENGINE vgaengine; + int hwcursor_size; + int CRT2_write_enable; + const char *chip_name; +} sisfb_chip_info[] __devinitdata = { + { SIS_300, SIS_300_VGA, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" }, + { SIS_540, SIS_300_VGA, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" }, + { SIS_630, SIS_300_VGA, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" }, + { SIS_315H, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315H" }, + { SIS_315, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315" }, + { SIS_315PRO, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315PRO" }, + { SIS_550, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 55x" }, + { SIS_650, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 65x" }, + { SIS_330, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" }, + { SIS_660, SIS_315_VGA, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" }, +}; + +static struct pci_device_id __devinitdata sisfb_pci_table[] = { +#ifdef CONFIG_FB_SIS_300 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, +#endif +#ifdef CONFIG_FB_SIS_315 + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, +#endif + { 0 } }; +MODULE_DEVICE_TABLE(pci, sisfb_pci_table); #define MD_SIS300 1 #define MD_SIS315 2 @@ -563,7 +601,11 @@ {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, MD_SIS300|MD_SIS315}, {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_SIS300|MD_SIS315}, - {"1280x960x8", 0x7c, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_SIS300|MD_SIS315}, + {"1280x800x8", 0x14, 0x0000, 0x0000, 1280, 800, 8, 1, 160, 50, MD_SIS315}, + {"1280x800x16", 0x15, 0x0000, 0x0000, 1280, 800, 16, 1, 160, 50, MD_SIS315}, + {"1280x800x24", 0x16, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x800x32", 0x16, 0x0000, 0x0000, 1280, 800, 32, 1, 160, 50, MD_SIS315}, + {"1280x960x8", 0x7c, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x960x16", 0x7d, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x960x24", 0x7e, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, {"1280x960x32", 0x7e, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_SIS300|MD_SIS315}, @@ -587,6 +629,10 @@ {"1600x1200x16", 0x3d, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315}, {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315}, + {"1680x1050x8", 0x17, 0x0000, 0x0000, 1680, 1050, 8, 1, 210, 65, MD_SIS315}, + {"1680x1050x16", 0x18, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65, MD_SIS315}, + {"1680x1050x24", 0x19, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, + {"1680x1050x32", 0x19, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65, MD_SIS315}, {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_SIS300|MD_SIS315}, {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315}, {"1920x1440x24", 0x6b, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315}, @@ -604,8 +650,6 @@ #else int sisfb_mode_idx = -1; /* Use a default mode if we are inside the kernel */ #endif -u8 sisfb_mode_no = 0; -u8 sisfb_rate_idx = 0; /* CR36 evaluation */ const USHORT sis300paneltype[] = @@ -620,15 +664,21 @@ LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, LCD_640x480_2, LCD_640x480_3, LCD_320x480, LCD_1024x768 }; +const USHORT sis661paneltype[] = + { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024, + LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960, + LCD_1152x768, LCD_1400x1050, LCD_1280x768, LCD_1600x1200, + LCD_1280x800, LCD_1680x1050, LCD_1280x720, LCD_1024x768 }; + #define FL_550_DSTN 0x01 #define FL_550_FSTN 0x02 -static const struct _sis_crt2type { +static struct _sis_crt2type { char name[10]; int type_no; int tvplug_no; unsigned short flags; -} sis_crt2type[] = { +} sis_crt2type[] __initdata = { {"NONE", 0, -1, 0}, {"LCD", CRT2_LCD, -1, 0}, {"TV", CRT2_TV, -1, 0}, @@ -642,10 +692,10 @@ }; /* Queue mode selection for 310 series */ -static const struct _sis_queuemode { +static struct _sis_queuemode { char name[6]; int type_no; -} sis_queuemode[] = { +} sis_queuemode[] __initdata = { {"AGP", AGP_CMD_QUEUE}, {"VRAM", VM_CMD_QUEUE}, {"MMIO", MMIO_CMD}, @@ -653,10 +703,10 @@ }; /* TV standard */ -static const struct _sis_tvtype { +static struct _sis_tvtype { char name[6]; int type_no; -} sis_tvtype[] = { +} sis_tvtype[] __initdata = { {"PAL", TV_PAL}, {"NTSC", TV_NTSC}, {"\0", -1} @@ -696,6 +746,7 @@ {1, 1152, 864, 75, TRUE}, {2, 1152, 864, 84, TRUE}, {1, 1280, 720, 60, TRUE}, {2, 1280, 720, 75, TRUE}, {3, 1280, 720, 85, TRUE}, {1, 1280, 768, 60, TRUE}, + {1, 1280, 800, 60, TRUE}, {1, 1280, 960, 60, TRUE}, {2, 1280, 960, 85, TRUE}, {1, 1280, 1024, 43, TRUE}, {2, 1280, 1024, 60, TRUE}, {3, 1280, 1024, 75, TRUE}, {4, 1280, 1024, 85, TRUE}, @@ -705,6 +756,7 @@ {1, 1600, 1200, 60, TRUE}, {2, 1600, 1200, 65, TRUE}, {3, 1600, 1200, 70, TRUE}, {4, 1600, 1200, 75, TRUE}, {5, 1600, 1200, 85, TRUE}, {6, 1600, 1200, 100, TRUE}, {7, 1600, 1200, 120, TRUE}, + {1, 1680, 1050, 60, TRUE}, {1, 1920, 1440, 60, TRUE}, {2, 1920, 1440, 65, TRUE}, {3, 1920, 1440, 70, TRUE}, {4, 1920, 1440, 75, TRUE}, {5, 1920, 1440, 85, TRUE}, {6, 1920, 1440, 100, TRUE}, {1, 2048, 1536, 60, TRUE}, {2, 2048, 1536, 65, TRUE}, {3, 2048, 1536, 70, TRUE}, @@ -764,18 +816,20 @@ static u8 sisfb_lastrates[128]; #endif -static const struct _chswtable { +#ifdef CONFIG_FB_SIS_300 +static struct _chswtable { int subsysVendor; int subsysCard; char *vendorName; char *cardName; -} mychswtable[] = { +} mychswtable[] __devinitdata = { { 0x1631, 0x1002, "Mitachi", "0x1002" }, { 0x1071, 0x7521, "Mitac" , "7521P" }, { 0, 0, "" , "" } }; +#endif -static const struct _customttable { +static struct _customttable { unsigned short chipID; char *biosversion; char *biosdate; @@ -788,7 +842,7 @@ char *cardName; unsigned long SpecialID; char *optionName; -} mycustomttable[] = { +} mycustomttable[] __devinitdata = { { SIS_630, "2.00.07", "09/27/2002-13:38:25", 0x3240A8, { 0x220, 0x227, 0x228, 0x229, 0x0ee }, @@ -917,40 +971,7 @@ } }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* Offscreen layout */ -typedef struct _SIS_GLYINFO { - unsigned char ch; - int fontwidth; - int fontheight; - u8 gmask[72]; - int ngmask; -} SIS_GLYINFO; -static char sisfb_fontname[40]; -#endif - -typedef struct _SIS_OH { - struct _SIS_OH *poh_next; - struct _SIS_OH *poh_prev; - unsigned long offset; - unsigned long size; -} SIS_OH; - -typedef struct _SIS_OHALLOC { - struct _SIS_OHALLOC *poha_next; - SIS_OH aoh[1]; -} SIS_OHALLOC; - -typedef struct _SIS_HEAP { - SIS_OH oh_free; - SIS_OH oh_used; - SIS_OH *poh_freelist; - SIS_OHALLOC *poha_chain; - unsigned long max_freesize; -} SIS_HEAP; - -static unsigned long sisfb_hwcursor_vbase; static unsigned long sisfb_heap_start; static unsigned long sisfb_heap_end; @@ -1208,7 +1229,7 @@ static void sisfb_pre_setmode(void); static void sisfb_post_setmode(void); -static char * sis_find_rom(void); +static char * sis_find_rom(struct pci_dev *pdev); static BOOLEAN sisfb_CheckVBRetrace(void); static BOOLEAN sisfbcheckvretracecrt2(void); static BOOLEAN sisfbcheckvretracecrt1(void); @@ -1224,10 +1245,6 @@ void sis_malloc(struct sis_memreq *req); void sis_free(unsigned long base); -/* Internal hardware access routines */ -void sisfb_set_reg4(u16 port, unsigned long data); -u32 sisfb_get_reg3(u16 port); - /* Chipset-dependent internal routines */ #ifdef CONFIG_FB_SIS_300 static int sisfb_get_dram_size_300(void); @@ -1252,9 +1269,9 @@ unsigned long offset, unsigned long set, unsigned long *value); /* Sensing routines */ -void SiS_Sense30x(void); -int SISDoSense(int tempbl, int tempbh, int tempcl, int tempch); -void SiS_SenseCh(void); +static void SiS_Sense30x(void); +static int SISDoSense(int tempbl, int tempbh, int tempcl, int tempch); +static void SiS_SenseCh(void); /* Routines from init.c/init301.c */ extern USHORT SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN); @@ -1268,6 +1285,8 @@ extern void SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable); extern void SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable); +extern BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo); + extern BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension, unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex); @@ -1286,6 +1305,6 @@ extern void SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr); extern void SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); extern void SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo); - - #endif + + diff -urN linux-2.4.25/drivers/video/sis/vgatypes.h linux-2.4.26/drivers/video/sis/vgatypes.h --- linux-2.4.25/drivers/video/sis/vgatypes.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/vgatypes.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -187,6 +184,7 @@ LCD_848x480, LCD_1280x800, LCD_1680x1050, + LCD_1280x720, LCD_CUSTOM, LCD_UNKNOWN } SIS_LCD_TYPE; @@ -220,25 +218,27 @@ /* of Linear VGA memory */ ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */ + SISIOADDRESS ulIOAddress; /* base I/O address of VGA ports (0x3B0) */ + UCHAR jChipType; /* Used to Identify SiS Graphics Chip */ /* defined in the data structure type */ /* "SIS_CHIP_TYPE" */ UCHAR jChipRevision; /* Used to Identify SiS Graphics Chip Revision */ + UCHAR ujVBChipID; /* the ID of video bridge */ /* defined in the data structure type */ /* "SIS_VB_CHIP_TYPE" */ #ifdef LINUX_KERNEL BOOLEAN Is301BDH; + ULONG ulCRT2LCDType; /* defined in the data structure type */ + /* "SIS_LCD_TYPE" */ #endif USHORT usExternalChip; /* NO VB or other video bridge (other than */ /* SiS video bridge) */ - ULONG ulCRT2LCDType; /* defined in the data structure type */ - /* "SIS_LCD_TYPE" */ - BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */ BOOLEAN bSkipDramSizing; /* True: Skip video memory sizing. */ @@ -254,12 +254,6 @@ /* Note : restore cR registers if */ /* bSkipDramSizing = TRUE */ #endif - - PSIS_QUERYSPACE pQueryVGAConfigSpace; /* Get/Set VGA Configuration */ - /* space */ - - PSIS_QUERYSPACE pQueryNorthBridgeSpace;/* Get/Set North Bridge */ - /* space */ }; #endif @@ -275,42 +269,44 @@ typedef struct _SISFB_INFO sisfb_info, *psisfb_info; struct _SISFB_INFO { - unsigned long sisfb_id; /* for identifying sisfb */ + CARD32 sisfb_id; /* for identifying sisfb */ #ifndef SISFB_ID #define SISFB_ID 0x53495346 /* Identify myself with 'SISF' */ #endif - int chip_id; /* PCI ID of detected chip */ - int memory; /* video memory in KB which sisfb manages */ - int heapstart; /* heap start (= sisfb "mem" argument) in KB */ - unsigned char fbvidmode; /* current sisfb mode */ + CARD32 chip_id; /* PCI ID of detected chip */ + CARD32 memory; /* video memory in KB which sisfb manages */ + CARD32 heapstart; /* heap start (= sisfb "mem" argument) in KB */ + CARD8 fbvidmode; /* current sisfb mode */ + + CARD8 sisfb_version; + CARD8 sisfb_revision; + CARD8 sisfb_patchlevel; + + CARD8 sisfb_caps; /* sisfb's capabilities */ - unsigned char sisfb_version; - unsigned char sisfb_revision; - unsigned char sisfb_patchlevel; + CARD32 sisfb_tqlen; /* turbo queue length (in KB) */ - unsigned char sisfb_caps; /* sisfb's capabilities */ + CARD32 sisfb_pcibus; /* The card's PCI ID */ + CARD32 sisfb_pcislot; + CARD32 sisfb_pcifunc; - int sisfb_tqlen; /* turbo queue length (in KB) */ + CARD8 sisfb_lcdpdc; - unsigned int sisfb_pcibus; /* The card's PCI ID */ - unsigned int sisfb_pcislot; - unsigned int sisfb_pcifunc; + CARD8 sisfb_lcda; - unsigned char sisfb_lcdpdc; - - unsigned char sisfb_lcda; + CARD32 sisfb_vbflags; + CARD32 sisfb_currentvbflags; - unsigned long sisfb_vbflags; - unsigned long sisfb_currentvbflags; + CARD32 sisfb_scalelcd; + CARD32 sisfb_specialtiming; - int sisfb_scalelcd; - unsigned long sisfb_specialtiming; + CARD8 sisfb_haveemi; + CARD8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; + CARD8 sisfb_haveemilcd; - unsigned char sisfb_haveemi; - unsigned char sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; - unsigned char sisfb_haveemilcd; + CARD8 sisfb_lcdpdca; - char reserved[213]; /* for future use */ + CARD8 reserved[212]; /* for future use */ }; #endif diff -urN linux-2.4.25/drivers/video/sis/vstruct.h linux-2.4.26/drivers/video/sis/vstruct.h --- linux-2.4.25/drivers/video/sis/vstruct.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/drivers/video/sis/vstruct.h 2004-04-14 06:05:40.000000000 -0700 @@ -31,13 +31,10 @@ * * 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) All advertising materials mentioning features or use of this software - * * must display the following acknowledgement: "This product includes - * * software developed by Thomas Winischhofer, Vienna, Austria." - * * 4) The name of the author may not be used to endorse or promote products + * * 3) The name of the author may not be used to endorse or promote products * * derived from this software without specific prior written permission. * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, @@ -164,7 +161,6 @@ { UCHAR Ext_ModeID; USHORT Ext_ModeFlag; - UCHAR Ext_ModeOffset; USHORT Ext_VESAID; UCHAR Ext_RESINFO; UCHAR VB_ExtTVFlickerIndex; @@ -180,6 +176,7 @@ UCHAR Ext_CRT1CRTC; UCHAR Ext_CRTVCLK; UCHAR Ext_CRT2CRTC; + UCHAR Ext_CRT2CRTC_NS; UCHAR ModeID; USHORT XRes; USHORT YRes; @@ -228,6 +225,8 @@ UCHAR YChar; } SiS_ModeResInfoStruct; + + typedef UCHAR DRAM4Type[4]; /* Defines for SiS_CustomT */ @@ -289,18 +288,21 @@ USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4; #endif BOOLEAN SiS_UseROM; - int SiS_CHOverScan; + BOOLEAN SiS_ROMNew; + BOOLEAN PanelSelfDetected; + int SiS_CHOverScan; BOOLEAN SiS_CHSOverScan; BOOLEAN SiS_ChSW; BOOLEAN SiS_UseLCDA; - int SiS_UseOEM; - ULONG SiS_CustomT; - USHORT SiS_Backup70xx; + int SiS_UseOEM; + ULONG SiS_CustomT; + USHORT SiS_Backup70xx; BOOLEAN HaveEMI; BOOLEAN HaveEMILCD; BOOLEAN OverruleEMI; UCHAR EMI_30,EMI_31,EMI_32,EMI_33; - UCHAR PDC; + SHORT PDC, PDCA; + UCHAR SiS_MyCR63; USHORT SiS_CRT1Mode; USHORT SiS_flag_clearbuffer; int SiS_RAMType; @@ -339,32 +341,19 @@ USHORT SiS_DDC_Port; USHORT SiS_DDC_Index; USHORT SiS_DDC_Data; + USHORT SiS_DDC_NData; USHORT SiS_DDC_Clk; - USHORT SiS_DDC_DataShift; + USHORT SiS_DDC_NClk; USHORT SiS_DDC_DeviceAddr; USHORT SiS_DDC_ReadAddr; USHORT SiS_DDC_SecAddr; - USHORT SiS_Panel800x600; - USHORT SiS_Panel1024x768; - USHORT SiS_Panel1280x1024; - USHORT SiS_Panel1600x1200; - USHORT SiS_Panel1280x960; - USHORT SiS_Panel1400x1050; - USHORT SiS_Panel320x480; - USHORT SiS_Panel1152x768; - USHORT SiS_Panel1280x768; - USHORT SiS_Panel1024x600; - USHORT SiS_Panel640x480; - USHORT SiS_Panel640x480_2; - USHORT SiS_Panel640x480_3; - USHORT SiS_Panel1152x864; - USHORT SiS_PanelCustom; - USHORT SiS_PanelBarco1366; - USHORT SiS_PanelMax; + USHORT SiS_ChrontelInit; + BOOLEAN SiS_SensibleSR11; + USHORT SiS661LCD2TableSize; + USHORT SiS_PanelMinLVDS; USHORT SiS_PanelMin301; - USHORT SiS_ChrontelInit; - + const SiS_StStruct *SiS_SModeIDTable; SiS_StandTableStruct *SiS_StandTable; const SiS_ExtStruct *SiS_EModeIDTable; @@ -373,11 +362,10 @@ const SiS_CRT1TableStruct *SiS_CRT1Table; const SiS_MCLKDataStruct *SiS_MCLKData_0; const SiS_MCLKDataStruct *SiS_MCLKData_1; - const SiS_VCLKDataStruct *SiS_VCLKData; - const SiS_VBVCLKDataStruct *SiS_VBVCLKData; + SiS_VCLKDataStruct *SiS_VCLKData; + SiS_VBVCLKDataStruct *SiS_VBVCLKData; const SiS_StResInfoStruct *SiS_StResInfo; const SiS_ModeResInfoStruct *SiS_ModeResInfo; - const UCHAR *SiS_ScreenOffset; const UCHAR *pSiS_OutputSelect; const UCHAR *pSiS_SoftSetting; @@ -407,6 +395,12 @@ const USHORT *pSiS_VideoSenseData2; const USHORT *pSiS_YCSenseData2; #endif + + const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl; + const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS; + + /* SiS bridge */ + const UCHAR *SiS_NTSCPhase; const UCHAR *SiS_PALPhase; const UCHAR *SiS_NTSCPhase2; @@ -418,29 +412,27 @@ const UCHAR *SiS_SpecialPhase; const UCHAR *SiS_SpecialPhaseM; const UCHAR *SiS_SpecialPhaseJ; - const SiS_LCDDataStruct *SiS_StLCD1024x768Data; const SiS_LCDDataStruct *SiS_ExtLCD1024x768Data; const SiS_LCDDataStruct *SiS_St2LCD1024x768Data; - const SiS_LCDDataStruct *SiS_StLCD1280x1024Data; + const SiS_LCDDataStruct *SiS_LCD1280x720Data; + const SiS_LCDDataStruct *SiS_StLCD1280x768_2Data; + const SiS_LCDDataStruct *SiS_ExtLCD1280x768_2Data; + const SiS_LCDDataStruct *SiS_LCD1280x768_3Data; + const SiS_LCDDataStruct *SiS_LCD1280x800Data; + const SiS_LCDDataStruct *SiS_LCD1280x960Data; const SiS_LCDDataStruct *SiS_ExtLCD1280x1024Data; const SiS_LCDDataStruct *SiS_St2LCD1280x1024Data; - const SiS_LCDDataStruct *SiS_NoScaleData1024x768; - const SiS_LCDDataStruct *SiS_NoScaleData1280x1024; - const SiS_LCDDataStruct *SiS_LCD1280x960Data; - const SiS_LCDDataStruct *SiS_NoScaleData1400x1050; - const SiS_LCDDataStruct *SiS_NoScaleData1600x1200; - const SiS_LCDDataStruct *SiS_NoScaleData1280x768; const SiS_LCDDataStruct *SiS_StLCD1400x1050Data; - const SiS_LCDDataStruct *SiS_StLCD1600x1200Data; - const SiS_LCDDataStruct *SiS_StLCD1280x768Data; const SiS_LCDDataStruct *SiS_ExtLCD1400x1050Data; + const SiS_LCDDataStruct *SiS_StLCD1600x1200Data; const SiS_LCDDataStruct *SiS_ExtLCD1600x1200Data; - const SiS_LCDDataStruct *SiS_ExtLCD1280x768Data; + const SiS_LCDDataStruct *SiS_LCD1680x1050Data; const SiS_LCDDataStruct *SiS_NoScaleData; const SiS_TVDataStruct *SiS_StPALData; const SiS_TVDataStruct *SiS_ExtPALData; const SiS_TVDataStruct *SiS_StNTSCData; const SiS_TVDataStruct *SiS_ExtNTSCData; + const SiS_TVDataStruct *SiS_St1HiTVData; const SiS_TVDataStruct *SiS_St2HiTVData; const SiS_TVDataStruct *SiS_ExtHiTVData; const SiS_TVDataStruct *SiS_St525iData; @@ -454,12 +446,22 @@ const UCHAR *SiS_HiTVExtTiming; const UCHAR *SiS_HiTVSt1Timing; const UCHAR *SiS_HiTVSt2Timing; - const UCHAR *SiS_HiTVTextTiming; const UCHAR *SiS_HiTVGroup3Data; const UCHAR *SiS_HiTVGroup3Simu; +#if 0 + const UCHAR *SiS_HiTVTextTiming; const UCHAR *SiS_HiTVGroup3Text; - const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl; - const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS; +#endif + + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3; + const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3; + + /* LVDS, Chrontel */ + const SiS_LVDSDataStruct *SiS_LVDS800x600Data_1; const SiS_LVDSDataStruct *SiS_LVDS800x600Data_2; const SiS_LVDSDataStruct *SiS_LVDS1024x768Data_1; @@ -481,14 +483,6 @@ const SiS_LVDSDataStruct *SiS_LVDS640x480Data_1; const SiS_LVDSDataStruct *SiS_LVDS640x480Data_2; const SiS_LVDSDataStruct *SiS_LVDS320x480Data_1; - const SiS_LVDSDataStruct *SiS_LCDA1024x768Data_1; - const SiS_LVDSDataStruct *SiS_LCDA1024x768Data_2; - const SiS_LVDSDataStruct *SiS_LCDA1280x1024Data_1; - const SiS_LVDSDataStruct *SiS_LCDA1280x1024Data_2; - const SiS_LVDSDataStruct *SiS_LCDA1400x1050Data_1; - const SiS_LVDSDataStruct *SiS_LCDA1400x1050Data_2; - const SiS_LVDSDataStruct *SiS_LCDA1600x1200Data_1; - const SiS_LVDSDataStruct *SiS_LCDA1600x1200Data_2; const SiS_LVDSDataStruct *SiS_LVDSXXXxXXXData_1; const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_1; const SiS_LVDSDataStruct *SiS_LVDSBARCO1366Data_2; @@ -505,6 +499,7 @@ const SiS_LVDSDataStruct *SiS_CHTVUPALNData; const SiS_LVDSDataStruct *SiS_CHTVOPALNData; const SiS_LVDSDataStruct *SiS_CHTVSOPALData; + const SiS_LVDSDesStruct *SiS_PanelType00_1; const SiS_LVDSDesStruct *SiS_PanelType01_1; const SiS_LVDSDesStruct *SiS_PanelType02_1; @@ -539,20 +534,11 @@ const SiS_LVDSDesStruct *SiS_PanelType0e_2; const SiS_LVDSDesStruct *SiS_PanelType0f_2; const SiS_LVDSDesStruct *SiS_PanelTypeNS_2; - - const SiS_LVDSDesStruct *LVDS1024x768Des_1; - const SiS_LVDSDesStruct *LVDS1280x1024Des_1; - const SiS_LVDSDesStruct *LVDS1400x1050Des_1; - const SiS_LVDSDesStruct *LVDS1600x1200Des_1; - const SiS_LVDSDesStruct *LVDS1024x768Des_2; - const SiS_LVDSDesStruct *LVDS1280x1024Des_2; - const SiS_LVDSDesStruct *LVDS1400x1050Des_2; - const SiS_LVDSDesStruct *LVDS1600x1200Des_2; - const SiS_LVDSDesStruct *SiS_CHTVUNTSCDesData; const SiS_LVDSDesStruct *SiS_CHTVONTSCDesData; const SiS_LVDSDesStruct *SiS_CHTVUPALDesData; const SiS_LVDSDesStruct *SiS_CHTVOPALDesData; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1800x600_1; const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11024x768_1; const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT11280x1024_1; @@ -593,44 +579,13 @@ const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_2_H; const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3; const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1640x480_3_H; + const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1320x480_1; const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UNTSC; const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1ONTSC; const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1UPAL; const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1OPAL; const SiS_LVDSCRT1DataStruct *SiS_CHTVCRT1SOPAL; - const SiS_LVDSCRT1DataStruct *SiS_LVDSCRT1320x480_1; - - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_1; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_1; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11400x1050_1; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11600x1200_1; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_1_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_1_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11400x1050_1_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11600x1200_1_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_2; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_2; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11400x1050_2; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11600x1200_2; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11024x768_2_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11280x1024_2_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11400x1050_2_H; - const SiS_LCDACRT1DataStruct *SiS_LCDACRT11600x1200_2_H; - - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_1; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_2; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_3; - const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_3; - const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC; const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC; const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL; @@ -640,6 +595,7 @@ const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALN; const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALN; const SiS_CHTVRegDataStruct *SiS_CHTVReg_SOPAL; + const UCHAR *SiS_CHTVVCLKUNTSC; const UCHAR *SiS_CHTVVCLKONTSC; const UCHAR *SiS_CHTVVCLKUPAL; @@ -650,9 +606,13 @@ const UCHAR *SiS_CHTVVCLKOPALN; const UCHAR *SiS_CHTVVCLKSOPAL; - USHORT PanelXRes; - USHORT PanelYRes; - + USHORT PanelXRes, PanelHT; + USHORT PanelYRes, PanelVT; + USHORT PanelHRS, PanelHRE; + USHORT PanelVRS, PanelVRE; + USHORT PanelVCLKIdx300; + USHORT PanelVCLKIdx315; + BOOLEAN UseCustomMode; BOOLEAN CRT1UsesCustomMode; USHORT CHDisplay; @@ -694,10 +654,11 @@ UCHAR Backup_1d; int UsePanelScaler; + int CenterScreen; USHORT CP_Vendor, CP_Product; BOOLEAN CP_HaveCustomData; - int CP_PreferredX, CP_PreferredY; + int CP_PreferredX, CP_PreferredY, CP_PreferredIndex; int CP_MaxX, CP_MaxY, CP_MaxClock; BOOLEAN CP_Supports64048075; int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */ diff -urN linux-2.4.25/fs/binfmt_elf.c linux-2.4.26/fs/binfmt_elf.c --- linux-2.4.25/fs/binfmt_elf.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/binfmt_elf.c 2004-04-14 06:05:40.000000000 -0700 @@ -479,7 +479,8 @@ goto out_free_ph; files = current->files; /* Refcounted so ok */ - if(unshare_files() < 0) + retval = unshare_files(); + if (retval < 0) goto out_free_ph; if (files == current->files) { put_files_struct(files); @@ -820,7 +821,8 @@ /* error cleanup */ out_free_dentry: allow_write_access(interpreter); - fput(interpreter); + if (interpreter) + fput(interpreter); out_free_interp: if (elf_interpreter) kfree(elf_interpreter); diff -urN linux-2.4.25/fs/devfs/base.c linux-2.4.26/fs/devfs/base.c --- linux-2.4.25/fs/devfs/base.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/devfs/base.c 2004-04-14 06:05:40.000000000 -0700 @@ -3549,7 +3549,7 @@ int err; if ( !(boot_options & OPTION_MOUNT) ) return; - err = do_mount ("none", "/dev", "devfs", 0, ""); + err = do_mount ("none", "/dev", "devfs", 0, NULL); if (err == 0) printk (KERN_INFO "Mounted devfs on /dev\n"); else PRINTK ("(): unable to mount devfs, err: %d\n", err); } /* End Function mount_devfs_fs */ diff -urN linux-2.4.25/fs/fat/inode.c linux-2.4.26/fs/fat/inode.c --- linux-2.4.25/fs/fat/inode.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/fat/inode.c 2004-04-14 06:05:40.000000000 -0700 @@ -421,11 +421,13 @@ * 0/ i_ino - for fast, reliable lookup if still in the cache * 1/ i_generation - to see if i_ino is still valid * bit 0 == 0 iff directory - * 2/ i_pos - if ino has changed, but still in cache (hi) - * 3/ i_pos - if ino has changed, but still in cache (low) - * 4/ i_logstart - to semi-verify inode found at i_location - * 5/ parent->i_logstart - maybe used to hunt for the file on disc + * 2/ i_pos(8-39) - if ino has changed, but still in cache + * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos + * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc * + * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum + * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits + * of i_logstart is used to store the directory entry offset. */ struct dentry *fat_fh_to_dentry(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent) @@ -436,7 +438,7 @@ if (fhtype != 3) return ERR_PTR(-ESTALE); - if (len < 6) + if (len < 5) return ERR_PTR(-ESTALE); /* We cannot find the parent, It better just *be* there */ @@ -444,13 +446,17 @@ return ERR_PTR(-ESTALE); inode = iget(sb, fh[0]); - if (!inode || is_bad_inode(inode) || - inode->i_generation != fh[1]) { - if (inode) iput(inode); + if (!inode || is_bad_inode(inode) || inode->i_generation != fh[1]) { + if (inode) + iput(inode); inode = NULL; } if (!inode) { - loff_t i_pos = ((loff_t)fh[2] << 32) | fh[3]; + loff_t i_pos; + int i_logstart = fh[3] & 0x0fffffff; + + i_pos = (loff_t)fh[2] << 8; + i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); /* try 2 - see if i_pos is in F-d-c * require i_logstart to be the same @@ -458,7 +464,7 @@ */ inode = fat_iget(sb, i_pos); - if (inode && MSDOS_I(inode)->i_logstart != fh[4]) { + if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { iput(inode); inode = NULL; } @@ -508,24 +514,26 @@ result->d_op = sb->s_root->d_op; result->d_flags |= DCACHE_NFSD_DISCONNECTED; return result; - - } int fat_dentry_to_fh(struct dentry *de, __u32 *fh, int *lenp, int needparent) { int len = *lenp; struct inode *inode = de->d_inode; + u32 ipos_h, ipos_m, ipos_l; - if (len < 6) + if (len < 5) return 255; /* no room */ - *lenp = 6; + + ipos_h = MSDOS_I(inode)->i_pos >> 8; + ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24; + ipos_l = (MSDOS_I(inode)->i_pos & 0x0f) << 28; + *lenp = 5; fh[0] = inode->i_ino; fh[1] = inode->i_generation; - fh[2] = (__u32)(MSDOS_I(inode)->i_pos >> 32); - fh[3] = (__u32)MSDOS_I(inode)->i_pos; - fh[4] = MSDOS_I(inode)->i_logstart; - fh[5] = MSDOS_I(de->d_parent->d_inode)->i_logstart; + fh[2] = ipos_h; + fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; + fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart; return 3; } diff -urN linux-2.4.25/fs/hfsplus/wrapper.c linux-2.4.26/fs/hfsplus/wrapper.c --- linux-2.4.25/fs/hfsplus/wrapper.c 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/fs/hfsplus/wrapper.c 2004-04-14 06:05:40.000000000 -0700 @@ -14,6 +14,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) #include #endif +#include #include "hfsplus_fs.h" #include "hfsplus_raw.h" @@ -45,7 +46,7 @@ return 0; wd->ablk_start = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART)); - extent = be32_to_cpu(*(u32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT)); + extent = be32_to_cpu(get_unaligned((u32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT))); wd->embed_start = (extent >> 16) & 0xFFFF; wd->embed_count = extent & 0xFFFF; diff -urN linux-2.4.25/fs/inode.c linux-2.4.26/fs/inode.c --- linux-2.4.25/fs/inode.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/inode.c 2004-04-14 06:05:40.000000000 -0700 @@ -319,7 +319,8 @@ if (!inode) return; spin_lock(&inode_lock); - __refile_inode(inode); + if (!(inode->i_state & I_LOCK)) + __refile_inode(inode); spin_unlock(&inode_lock); } diff -urN linux-2.4.25/fs/isofs/rock.c linux-2.4.26/fs/isofs/rock.c --- linux-2.4.25/fs/isofs/rock.c 2002-02-25 11:38:08.000000000 -0800 +++ linux-2.4.26/fs/isofs/rock.c 2004-04-14 06:05:40.000000000 -0700 @@ -14,6 +14,7 @@ #include #include #include +#include #include "rock.h" @@ -419,7 +420,7 @@ return 0; } -static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr) +static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) { int slen; int rootflag; @@ -431,16 +432,25 @@ rootflag = 0; switch (slp->flags & ~1) { case 0: + if (slp->len > plimit - rpnt) + return NULL; memcpy(rpnt, slp->text, slp->len); rpnt+=slp->len; break; + case 2: + if (rpnt >= plimit) + return NULL; + *rpnt++='.'; + break; case 4: + if (2 > plimit - rpnt) + return NULL; *rpnt++='.'; - /* fallthru */ - case 2: *rpnt++='.'; break; case 8: + if (rpnt >= plimit) + return NULL; rootflag = 1; *rpnt++='/'; break; @@ -457,17 +467,23 @@ * If there is another SL record, and this component * record isn't continued, then add a slash. */ - if ((!rootflag) && (rr->u.SL.flags & 1) && !(oldslp->flags & 1)) + if ((!rootflag) && (rr->u.SL.flags & 1) && + !(oldslp->flags & 1)) { + if (rpnt >= plimit) + return NULL; *rpnt++='/'; + } break; } /* * If this component record isn't continued, then append a '/'. */ - if (!rootflag && !(oldslp->flags & 1)) + if (!rootflag && !(oldslp->flags & 1)) { + if (rpnt >= plimit) + return NULL; *rpnt++='/'; - + } } return rpnt; } @@ -548,7 +564,10 @@ CHECK_SP(goto out); break; case SIG('S', 'L'): - rpnt = get_symlink_chunk(rpnt, rr); + rpnt = get_symlink_chunk(rpnt, rr, + link + (PAGE_SIZE - 1)); + if (rpnt == NULL) + goto out; break; case SIG('C', 'E'): /* This tells is if there is a continuation record */ diff -urN linux-2.4.25/fs/jbd/journal.c linux-2.4.26/fs/jbd/journal.c --- linux-2.4.25/fs/jbd/journal.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/jbd/journal.c 2004-04-14 06:05:40.000000000 -0700 @@ -671,6 +671,7 @@ bh = getblk(journal->j_dev, blocknr, journal->j_blocksize); lock_buffer(bh); + memset(bh->b_data, 0, journal->j_blocksize); BUFFER_TRACE(bh, "return this buffer"); return journal_add_journal_head(bh); } diff -urN linux-2.4.25/fs/jfs/jfs_dmap.c linux-2.4.26/fs/jfs/jfs_dmap.c --- linux-2.4.25/fs/jfs/jfs_dmap.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_dmap.c 2004-04-14 06:05:40.000000000 -0700 @@ -125,7 +125,7 @@ s64 * results); static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results); -int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks); +static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks); static int dbFindBits(u32 word, int l2nb); static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno); static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx); @@ -135,10 +135,10 @@ int nblocks); static int dbMaxBud(u8 * cp); s64 dbMapFileSizeToMapSize(struct inode *ipbmap); -int blkstol2(s64 nb); +static int blkstol2(s64 nb); -int cntlz(u32 value); -int cnttz(u32 word); +static int cntlz(u32 value); +static int cnttz(u32 word); static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno, int nblocks); @@ -156,7 +156,7 @@ * into the table, with the table elements yielding the maximum * binary buddy of free bits within the character. */ -signed char budtab[256] = { +static s8 budtab[256] = { 3, 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, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -943,7 +943,7 @@ return (rc); } - +#ifdef _NOTYET /* * NAME: dbAllocExact() * @@ -1010,7 +1010,7 @@ return (rc); } - +#endif /* _NOTYET */ /* * NAME: dbReAlloc() @@ -1093,7 +1093,7 @@ * -ENOSPC - insufficient disk resources * -EIO - i/o error */ -int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) +static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) { struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); s64 lblkno, lastblkno, extblkno; @@ -1527,6 +1527,7 @@ if (n == 4) { jfs_error(bmp->db_ipbmap->i_sb, "dbAllocAG: failed descending stree"); + release_metapage(mp); return -EIO; } } @@ -3023,7 +3024,7 @@ * RETURN VALUES: * count of trailing zeros */ -int cnttz(u32 word) +static int cnttz(u32 word) { int n; @@ -3048,7 +3049,7 @@ * RETURN VALUES: * count of leading zeros */ -int cntlz(u32 value) +static int cntlz(u32 value) { int n; @@ -3311,7 +3312,7 @@ int i, i0 = TRUE, j, j0 = TRUE, k, n; s64 newsize; s64 p; - struct metapage *mp, *l2mp, *l1mp, *l0mp; + struct metapage *mp, *l2mp, *l1mp = NULL, *l0mp = NULL; struct dmapctl *l2dcp, *l1dcp, *l0dcp; struct dmap *dp; s8 *l0leaf, *l1leaf, *l2leaf; @@ -3514,6 +3515,7 @@ */ *l1leaf = dbInitDmapCtl(l0dcp, 0, ++i); write_metapage(l0mp); + l0mp = NULL; if (nblocks) l1leaf++; /* continue for next L0 */ @@ -3537,6 +3539,7 @@ */ *l2leaf = dbInitDmapCtl(l1dcp, 1, ++j); write_metapage(l1mp); + l1mp = NULL; if (nblocks) l2leaf++; /* continue for next L1 */ @@ -3555,17 +3558,20 @@ jfs_error(ipbmap->i_sb, "dbExtendFS: function has not returned as expected"); +errout: + if (l0mp) + release_metapage(l0mp); + if (l1mp) + release_metapage(l1mp); + release_metapage(l2mp); return -EIO; /* * finalize bmap control page */ - finalize: +finalize: return 0; - - errout: - return -EIO; } diff -urN linux-2.4.25/fs/jfs/jfs_dmap.h linux-2.4.26/fs/jfs/jfs_dmap.h --- linux-2.4.25/fs/jfs/jfs_dmap.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_dmap.h 2004-04-14 06:05:40.000000000 -0700 @@ -286,8 +286,6 @@ extern int dbAlloc(struct inode *ipbmap, s64 hint, s64 nblocks, s64 * results); -extern int dbAllocExact(struct inode *ip, s64 blkno, int nblocks); - extern int dbReAlloc(struct inode *ipbmap, s64 blkno, s64 nblocks, s64 addnblocks, s64 * results); diff -urN linux-2.4.25/fs/jfs/jfs_dtree.c linux-2.4.26/fs/jfs/jfs_dtree.c --- linux-2.4.25/fs/jfs/jfs_dtree.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_dtree.c 2004-04-14 06:05:40.000000000 -0700 @@ -162,9 +162,6 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, struct metapage * fmp, dtpage_t * fp, struct btstack * btstack); -static int dtSearchNode(struct inode *ip, - s64 lmxaddr, pxd_t * kpxd, struct btstack * btstack); - static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p); static int dtReadFirst(struct inode *ip, struct btstack * btstack); @@ -1426,8 +1423,10 @@ */ if (nextbn != 0) { DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc); - if (rc) + if (rc) { + discard_metapage(rmp); return rc; + } BT_MARK_DIRTY(mp, ip); /* @@ -2238,8 +2237,10 @@ pxdlock->index = 1; /* update sibling pointers */ - if ((rc = dtRelink(tid, ip, fp))) + if ((rc = dtRelink(tid, ip, fp))) { + BT_PUTPAGE(fmp); return rc; + } xlen = lengthPXD(&fp->header.self); ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); @@ -2310,8 +2311,10 @@ pxdlock->index = 1; /* update sibling pointers */ - if ((rc = dtRelink(tid, ip, p))) + if ((rc = dtRelink(tid, ip, p))) { + DT_PUTPAGE(mp); return rc; + } xlen = lengthPXD(&p->header.self); ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen); @@ -2380,7 +2383,7 @@ return 0; } - +#ifdef _NOTYET /* * NAME: dtRelocate() * @@ -2575,7 +2578,6 @@ return rc; } - /* * NAME: dtSearchNode() * @@ -2625,8 +2627,10 @@ /* * descend down to leftmost child page */ - if (p->header.flag & BT_LEAF) + if (p->header.flag & BT_LEAF) { + DT_PUTPAGE(mp); return -ESTALE; + } /* get the leftmost entry */ stbl = DT_GETSTBL(p); @@ -2677,7 +2681,7 @@ goto loop; } - +#endif /* _NOTYET */ /* * dtRelink() @@ -2933,7 +2937,7 @@ /* * function to determine next variable-sized jfs_dirent in buffer */ -inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent) +static inline struct jfs_dirent *next_jfs_dirent(struct jfs_dirent *dirent) { return (struct jfs_dirent *) ((char *)dirent + diff -urN linux-2.4.25/fs/jfs/jfs_dtree.h linux-2.4.26/fs/jfs/jfs_dtree.h --- linux-2.4.25/fs/jfs/jfs_dtree.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_dtree.h 2004-04-14 06:05:40.000000000 -0700 @@ -265,9 +265,6 @@ extern int dtDelete(tid_t tid, struct inode *ip, struct component_name * key, ino_t * data, int flag); -extern int dtRelocate(tid_t tid, - struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr); - extern int dtModify(tid_t tid, struct inode *ip, struct component_name * key, ino_t * orig_ino, ino_t new_ino, int flag); diff -urN linux-2.4.25/fs/jfs/jfs_extent.c linux-2.4.26/fs/jfs/jfs_extent.c --- linux-2.4.25/fs/jfs/jfs_extent.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_extent.c 2004-04-14 06:05:40.000000000 -0700 @@ -35,7 +35,6 @@ /* * external references */ -extern int dbExtend(struct inode *, s64, s64, s64); extern int jfs_commit_inode(struct inode *, int); diff -urN linux-2.4.25/fs/jfs/jfs_imap.c linux-2.4.26/fs/jfs/jfs_imap.c --- linux-2.4.25/fs/jfs/jfs_imap.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_imap.c 2004-04-14 06:05:40.000000000 -0700 @@ -1552,6 +1552,7 @@ 0); if (rem >= INOSPEREXT) { IREAD_UNLOCK(ipimap); + release_metapage(mp); AG_UNLOCK(imap, agno); jfs_error(ip->i_sb, "diAlloc: can't find free bit " @@ -1846,6 +1847,7 @@ */ if (!iagp->nfreeinos) { IREAD_UNLOCK(imap->im_ipimap); + release_metapage(mp); jfs_error(ip->i_sb, "diAllocIno: nfreeinos = 0, but iag on freelist"); return -EIO; @@ -1857,6 +1859,7 @@ for (sword = 0;; sword++) { if (sword >= SMAPSZ) { IREAD_UNLOCK(imap->im_ipimap); + release_metapage(mp); jfs_error(ip->i_sb, "diAllocIno: free inode not found in summary map"); return -EIO; @@ -1872,6 +1875,7 @@ rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0); if (rem >= EXTSPERSUM) { IREAD_UNLOCK(imap->im_ipimap); + release_metapage(mp); jfs_error(ip->i_sb, "diAllocIno: no free extent found"); return -EIO; } @@ -1882,6 +1886,7 @@ rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0); if (rem >= INOSPEREXT) { IREAD_UNLOCK(imap->im_ipimap); + release_metapage(mp); jfs_error(ip->i_sb, "diAllocIno: free inode not found"); return -EIO; } @@ -2847,12 +2852,14 @@ * and should be free in persistent map; */ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { + release_metapage(mp); jfs_error(ipimap->i_sb, "diUpdatePMap: the inode is not allocated in " "the working map"); return -EIO; } if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) { + release_metapage(mp); jfs_error(ipimap->i_sb, "diUpdatePMap: the inode is not free in the " "persistent map"); diff -urN linux-2.4.25/fs/jfs/jfs_logmgr.c linux-2.4.26/fs/jfs/jfs_logmgr.c --- linux-2.4.25/fs/jfs/jfs_logmgr.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_logmgr.c 2004-04-14 06:05:40.000000000 -0700 @@ -185,6 +185,7 @@ static void lbmIODone(struct buffer_head *bh, int); static void lbmStartIO(struct lbuf * bp); static void lmGCwrite(struct jfs_log * log, int cant_block); +static int lmLogSync(struct jfs_log * log, int nosyncwait); /* @@ -799,7 +800,7 @@ * NOTE: * This routine is called a interrupt time by lbmIODone */ -void lmPostGC(struct lbuf * bp) +static void lmPostGC(struct lbuf * bp) { unsigned long flags; struct jfs_log *log = bp->l_log; @@ -922,7 +923,7 @@ * * serialization: LOG_LOCK() held on entry/exit */ -int lmLogSync(struct jfs_log * log, int nosyncwait) +static int lmLogSync(struct jfs_log * log, int nosyncwait) { int logsize; int written; /* written since last syncpt */ @@ -1697,7 +1698,7 @@ if (lbuf == 0) goto error; lbuf->l_bh.b_data = lbuf->l_ldata = - (char *) __get_free_page(GFP_KERNEL); + (char *) get_zeroed_page(GFP_KERNEL); if (lbuf->l_ldata == 0) { kfree(lbuf); goto error; diff -urN linux-2.4.25/fs/jfs/jfs_logmgr.h linux-2.4.26/fs/jfs/jfs_logmgr.h --- linux-2.4.25/fs/jfs/jfs_logmgr.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_logmgr.h 2004-04-14 06:05:40.000000000 -0700 @@ -509,7 +509,6 @@ extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log); extern int lmLogClose(struct super_block *sb, struct jfs_log * log); -extern int lmLogSync(struct jfs_log * log, int nosyncwait); extern int lmLogShutdown(struct jfs_log * log); extern int lmLogInit(struct jfs_log * log); extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize); diff -urN linux-2.4.25/fs/jfs/jfs_metapage.c linux-2.4.26/fs/jfs/jfs_metapage.c --- linux-2.4.25/fs/jfs/jfs_metapage.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_metapage.c 2004-04-14 06:05:40.000000000 -0700 @@ -385,6 +385,10 @@ } mp->data = kmap(mp->page) + page_offset; } + + if (new) + memset(mp->data, 0, PSIZE); + jfs_info("__get_metapage: returning = 0x%p", mp); return mp; diff -urN linux-2.4.25/fs/jfs/jfs_txnmgr.c linux-2.4.26/fs/jfs/jfs_txnmgr.c --- linux-2.4.25/fs/jfs/jfs_txnmgr.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_txnmgr.c 2004-04-14 06:05:40.000000000 -0700 @@ -167,25 +167,23 @@ /* * forward references */ -int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck, struct commit * cd); -int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void inlineLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); -void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck); +static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck, struct commit * cd); +static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); +static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); +static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck); static void txAbortCommit(struct commit * cd); static void txAllocPMap(struct inode *ip, struct maplock * maplock, - struct tblock * tblk); -void txForce(struct tblock * tblk); -static int txLog(struct jfs_log * log, struct tblock * tblk, struct commit * cd); -int txMoreLock(void); + struct tblock * tblk); +static void txForce(struct tblock * tblk); +static int txLog(struct jfs_log * log, struct tblock * tblk, + struct commit * cd); static void txUpdateMap(struct tblock * tblk); static void txRelease(struct tblock * tblk); -void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck); static void LogSyncRelease(struct metapage * mp); @@ -1338,9 +1336,6 @@ lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset); lrd->log.redopage.inode = cpu_to_le32(ip->i_ino); - if (tlck->mp) - hold_metapage(tlck->mp, 0); - /* write log record of page from the tlock */ switch (tlck->type & tlckTYPE) { case tlckXTREE: @@ -1366,8 +1361,6 @@ default: jfs_err("UFO tlock:0x%p", tlck); } - if (tlck->mp) - release_metapage(tlck->mp); } return rc; @@ -1379,7 +1372,7 @@ * * function: log inode tlock and format maplock to update bmap; */ -int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck, struct commit * cd) { int rc = 0; @@ -1494,7 +1487,7 @@ * * function: log data tlock */ -int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct metapage *mp; @@ -1517,6 +1510,7 @@ * the last entry, so don't bother logging this */ mp->lid = 0; + hold_metapage(mp, 0); atomic_dec(&mp->nohomeok); discard_metapage(mp); tlck->mp = 0; @@ -1540,7 +1534,7 @@ * * function: log dtree tlock and format maplock to update bmap; */ -void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct metapage *mp; @@ -1645,7 +1639,7 @@ * * function: log xtree tlock and format maplock to update bmap; */ -void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, +static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, struct tlock * tlck) { struct inode *ip; @@ -2705,7 +2699,7 @@ * allocation maps are updated in order. For synchronous transactions, * let the user thread finish processing after txUpdateMap() is called. */ -void txLazyCommit(struct tblock * tblk) +static void txLazyCommit(struct tblock * tblk) { struct jfs_log *log; @@ -2987,11 +2981,12 @@ anon_inode_list); ip = jfs_ip->inode; - /* - * down_trylock returns 0 on success. This is - * inconsistent with spin_trylock. - */ - if (! down_trylock(&jfs_ip->commit_sem)) { + if (! igrab(ip)) { + /* + * Inode is being freed + */ + list_del_init(&jfs_ip->anon_inode_list); + } else if (! down_trylock(&jfs_ip->commit_sem)) { /* * inode will be removed from anonymous list * when it is committed @@ -3001,6 +2996,8 @@ rc = txCommit(tid, 1, &ip, 0); txEnd(tid); up(&jfs_ip->commit_sem); + + iput(ip); /* * Just to be safe. I don't know how * long we can run without blocking @@ -3020,6 +3017,10 @@ /* Put on anon_list2 */ list_add(&jfs_ip->anon_inode_list, &TxAnchor.anon_list2); + + TXN_UNLOCK(); + iput(ip); + TXN_LOCK(); } } /* Add anon_list2 back to anon_list */ diff -urN linux-2.4.25/fs/jfs/jfs_unicode.c linux-2.4.26/fs/jfs/jfs_unicode.c --- linux-2.4.25/fs/jfs/jfs_unicode.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_unicode.c 2004-04-14 06:05:40.000000000 -0700 @@ -56,8 +56,8 @@ * FUNCTION: Convert character string to unicode string * */ -int jfs_strtoUCS(wchar_t * to, - const char *from, int len, struct nls_table *codepage) +static int jfs_strtoUCS(wchar_t * to, const char *from, int len, + struct nls_table *codepage) { int charlen; int i; diff -urN linux-2.4.25/fs/jfs/jfs_xtree.c linux-2.4.26/fs/jfs/jfs_xtree.c --- linux-2.4.25/fs/jfs/jfs_xtree.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_xtree.c 2004-04-14 06:05:40.000000000 -0700 @@ -1032,11 +1032,11 @@ rc = (sp->header.flag & BT_ROOT) ? xtSplitRoot(tid, ip, split, &rmp) : xtSplitPage(tid, ip, split, &rmp, &rbn); - if (rc) - return -EIO; XT_PUTPAGE(smp); + if (rc) + return -EIO; /* * propagate up the router entry for the leaf page just split * @@ -1611,14 +1611,16 @@ /* there must exist extent to be extended */ if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT))) return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + if (cmp != 0) { + XT_PUTPAGE(mp); jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent"); return -EIO; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); - /* extension must be contiguous */ xad = &p->xad[index]; if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) { @@ -1677,25 +1679,27 @@ * resides on the new child page; */ if (rootsplit) { - if (p->header.nextindex == - cpu_to_le16(XTENTRYSTART + 1)) { - xad = &p->xad[XTENTRYSTART]; - bn = addressXAD(xad); - - /* get new child page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - - BT_MARK_DIRTY(mp, ip); - if (!test_cflag(COMMIT_Nolink, ip)) { - tlck = txLock(tid, ip, mp, - tlckXTREE | - tlckGROW); - xtlck = (struct xtlock *) & tlck->lock; - } + ASSERT(p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)); + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW); + xtlck = (struct xtlock *) & tlck->lock; } - } else + } else { /* get back old page */ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + } } /* * insert the new entry into the leaf page @@ -1736,7 +1740,7 @@ return rc; } - +#ifdef _NOTYET /* * xtTailgate() * @@ -1778,14 +1782,16 @@ /* there must exist extent to be tailgated */ if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + if (cmp != 0) { + XT_PUTPAGE(mp); jfs_error(ip->i_sb, "xtTailgate: couldn't find extent"); return -EIO; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); - /* entry found must be last entry */ nextindex = le16_to_cpu(p->header.nextindex); if (index != nextindex - 1) { @@ -1843,25 +1849,27 @@ * resides on the new child page; */ if (rootsplit) { - if (p->header.nextindex == - cpu_to_le16(XTENTRYSTART + 1)) { - xad = &p->xad[XTENTRYSTART]; - bn = addressXAD(xad); - - /* get new child page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - - BT_MARK_DIRTY(mp, ip); - if (!test_cflag(COMMIT_Nolink, ip)) { - tlck = txLock(tid, ip, mp, - tlckXTREE | - tlckGROW); - xtlck = (struct xtlock *) & tlck->lock; - } + ASSERT(p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)); + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW); + xtlck = (struct xtlock *) & tlck->lock; } - } else + } else { /* get back old page */ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + } } /* * insert the new entry into the leaf page @@ -1918,7 +1926,7 @@ return rc; } - +#endif /* _NOTYET */ /* * xtUpdate() @@ -1960,14 +1968,15 @@ if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) return rc; + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); + if (cmp != 0) { + XT_PUTPAGE(mp); jfs_error(ip->i_sb, "xtUpdate: Could not find extent"); return -EIO; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); - BT_MARK_DIRTY(mp, ip); /* * acquire tlock of the leaf page containing original entry @@ -2175,25 +2184,26 @@ * resides on the new child page; */ if (rootsplit) { - if (p->header.nextindex == - cpu_to_le16(XTENTRYSTART + 1)) { - xad = &p->xad[XTENTRYSTART]; - bn = addressXAD(xad); - - /* get new child page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - - BT_MARK_DIRTY(mp, ip); - if (!test_cflag(COMMIT_Nolink, ip)) { - tlck = txLock(tid, ip, mp, - tlckXTREE | - tlckGROW); - xtlck = (struct xtlock *) & tlck->lock; - } + ASSERT(p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)); + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW); + xtlck = (struct xtlock *) & tlck->lock; } } else { /* get back old page */ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; /* is nXAD on new page ? */ if (newindex > @@ -2247,6 +2257,8 @@ /* get new right page */ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; BT_MARK_DIRTY(mp, ip); if (!test_cflag(COMMIT_Nolink, ip)) { @@ -2270,13 +2282,16 @@ if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); + if (cmp != 0) { + XT_PUTPAGE(mp); jfs_error(ip->i_sb, "xtUpdate: xtSearch failed"); return -EIO; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); if (index0 != index) { XT_PUTPAGE(mp); jfs_error(ip->i_sb, @@ -2325,25 +2340,27 @@ * resides on the new child page; */ if (rootsplit) { - if (p->header.nextindex == - cpu_to_le16(XTENTRYSTART + 1)) { - xad = &p->xad[XTENTRYSTART]; - bn = addressXAD(xad); - - /* get new child page */ - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - - BT_MARK_DIRTY(mp, ip); - if (!test_cflag(COMMIT_Nolink, ip)) { - tlck = txLock(tid, ip, mp, - tlckXTREE | - tlckGROW); - xtlck = (struct xtlock *) & tlck->lock; - } + ASSERT(p->header.nextindex == + cpu_to_le16(XTENTRYSTART + 1)); + xad = &p->xad[XTENTRYSTART]; + bn = addressXAD(xad); + + /* get new child page */ + XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + + BT_MARK_DIRTY(mp, ip); + if (!test_cflag(COMMIT_Nolink, ip)) { + tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW); + xtlck = (struct xtlock *) & tlck->lock; } - } else + } else { /* get back old page */ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); + if (rc) + return rc; + } } else { /* if insert into middle, shift right remaining entries */ if (newindex < nextindex) @@ -2660,8 +2677,10 @@ /* * free non-root leaf page */ - if ((rc = xtRelink(tid, ip, fp))) + if ((rc = xtRelink(tid, ip, fp))) { + XT_PUTPAGE(fmp); return rc; + } xaddr = addressPXD(&fp->header.self); xlen = lengthPXD(&fp->header.self); @@ -2703,7 +2722,7 @@ p->header.nextindex = cpu_to_le16(XTENTRYSTART); - /* XT_PUTPAGE(fmp); */ + /* XT_PUTPAGE(mp); */ break; } else { @@ -2717,7 +2736,7 @@ (s64) JFS_SBI(ip->i_sb)->nbperpage); /* unpin/free the buffer page */ - discard_metapage(fmp); + discard_metapage(mp); /* propagate up */ continue; @@ -2826,14 +2845,15 @@ rc = xtSearch(ip, xoff, &cmp, &btstack, 0); if (rc) return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + if (cmp) { XT_PUTPAGE(pmp); return -ESTALE; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); - /* validate for exact match with a single entry */ xad = &pp->xad[index]; if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) { @@ -2846,14 +2866,15 @@ rc = xtSearchNode(ip, oxad, &cmp, &btstack, 0); if (rc) return rc; + + /* retrieve search result */ + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); + if (cmp) { XT_PUTPAGE(pmp); return -ESTALE; } - /* retrieve search result */ - XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); - /* xtSearchNode() validated for exact match with a single entry */ xad = &pp->xad[index]; @@ -2927,7 +2948,9 @@ } /* get back parent page */ - rc = xtSearch(ip, xoff, &cmp, &btstack, 0); + if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0))) + return rc; + XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index); jfs_info("xtRelocate: target data extent relocated."); } else { /* (xtype == XTPAGE) */ @@ -3150,8 +3173,10 @@ XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); if (rc) return rc; - if (p->header.flag & BT_LEAF) + if (p->header.flag & BT_LEAF) { + XT_PUTPAGE(mp); return -ESTALE; + } lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART; @@ -3949,12 +3974,15 @@ rc = xtSearch(ip, xoff, &cmp, &btstack, 0); if (rc) return rc; + + XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); + if (cmp != 0) { + XT_PUTPAGE(mp); jfs_error(ip->i_sb, "xtTruncate_pmap: did not find extent"); return -EIO; } - XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); } else { /* * start with root @@ -4202,17 +4230,10 @@ int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p) { int rc = 0; - struct metapage *mp; xad_t *xad; s64 xaddr, xoff; int xlen, i, j; - if (p == NULL) { - XT_GETPAGE(ip, bn, mp, PSIZE, p, rc); - if (rc) - return rc; - } - /* display page control */ printf("bn:0x%lx flag:0x%x nextindex:%d\n", (ulong) bn, p->header.flag, diff -urN linux-2.4.25/fs/jfs/jfs_xtree.h linux-2.4.26/fs/jfs/jfs_xtree.h --- linux-2.4.25/fs/jfs/jfs_xtree.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/jfs/jfs_xtree.h 2004-04-14 06:05:40.000000000 -0700 @@ -117,8 +117,10 @@ int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag); extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen, int flag); +#ifdef _NOTYET extern int xtTailgate(tid_t tid, struct inode *ip, s64 xoff, int xlen, s64 xaddr, int flag); +#endif extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad); extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen, int flag); diff -urN linux-2.4.25/fs/jfs/namei.c linux-2.4.26/fs/jfs/namei.c --- linux-2.4.25/fs/jfs/namei.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/jfs/namei.c 2004-04-14 06:05:40.000000000 -0700 @@ -42,7 +42,7 @@ struct inode_operations jfs_dir_inode_operations; struct file_operations jfs_dir_operations; -s64 commitZeroLink(tid_t, struct inode *); +static s64 commitZeroLink(tid_t, struct inode *); /* * NAME: jfs_create(dip, dentry, mode) @@ -57,7 +57,7 @@ * RETURN: Errors from subroutines * */ -int jfs_create(struct inode *dip, struct dentry *dentry, int mode) +static int jfs_create(struct inode *dip, struct dentry *dentry, int mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -172,7 +172,7 @@ * note: * EACCESS: user needs search+write permission on the parent directory */ -int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) +static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) { int rc = 0; tid_t tid; /* transaction id */ @@ -300,7 +300,7 @@ * but the directory is not removed until the last reference to * the directory is released (cf.unlink() of regular file). */ -int jfs_rmdir(struct inode *dip, struct dentry *dentry) +static int jfs_rmdir(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ @@ -423,7 +423,7 @@ * JFS does NOT support unlink() on directories. * */ -int jfs_unlink(struct inode *dip, struct dentry *dentry) +static int jfs_unlink(struct inode *dip, struct dentry *dentry) { int rc; tid_t tid; /* transaction id */ @@ -576,7 +576,7 @@ * * RETURN: Errors from subroutines */ -s64 commitZeroLink(tid_t tid, struct inode *ip) +static s64 commitZeroLink(tid_t tid, struct inode *ip) { int filetype; struct tblock *tblk; @@ -744,7 +744,7 @@ * EXDEV: target object and new link are on different file systems and * implementation does not support links between file systems [XPG4.2]. */ -int jfs_link(struct dentry *old_dentry, +static int jfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { int rc; @@ -832,7 +832,8 @@ * an intermediate result whose length exceeds PATH_MAX [XPG4.2] */ -int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name) +static int jfs_symlink(struct inode *dip, struct dentry *dentry, + const char *name) { int rc; tid_t tid; @@ -1033,7 +1034,7 @@ * * FUNCTION: rename a file or directory */ -int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, +static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct btstack btstack; @@ -1303,7 +1304,8 @@ * * FUNCTION: Create a special file (device) */ -int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +static int jfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, int rdev) { struct btstack btstack; struct component_name dname; diff -urN linux-2.4.25/fs/jfs/super.c linux-2.4.26/fs/jfs/super.c --- linux-2.4.25/fs/jfs/super.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/jfs/super.c 2004-04-14 06:05:40.000000000 -0700 @@ -265,7 +265,7 @@ return 0; } -int jfs_remount(struct super_block *sb, int *flags, char *data) +static int jfs_remount(struct super_block *sb, int *flags, char *data) { s64 newLVSize = 0; int rc = 0; @@ -481,10 +481,10 @@ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { + memset(jfs_ip, 0, sizeof(struct jfs_inode_info)); INIT_LIST_HEAD(&jfs_ip->anon_inode_list); init_rwsem(&jfs_ip->rdwrlock); init_MUTEX(&jfs_ip->commit_sem); - jfs_ip->atlhead = 0; jfs_ip->active_ag = -1; } } diff -urN linux-2.4.25/fs/lockd/svc4proc.c linux-2.4.26/fs/lockd/svc4proc.c --- linux-2.4.25/fs/lockd/svc4proc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/lockd/svc4proc.c 2004-04-14 06:05:40.000000000 -0700 @@ -471,7 +471,7 @@ dprintk("lockd: GRANTED_RES called\n"); - nlmsvc_grant_reply(&argp->cookie, argp->status); + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); return rpc_success; } diff -urN linux-2.4.25/fs/lockd/svclock.c linux-2.4.26/fs/lockd/svclock.c --- linux-2.4.25/fs/lockd/svclock.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/lockd/svclock.c 2004-04-14 06:05:40.000000000 -0700 @@ -113,11 +113,11 @@ (long long)lock->fl.fl_end, lock->fl.fl_type); for (head = &nlm_blocked; (block = *head); head = &block->b_next) { fl = &block->b_call.a_args.lock.fl; - dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%x\n", + dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", block->b_file, fl->fl_pid, (long long)fl->fl_start, (long long)fl->fl_end, fl->fl_type, - *(unsigned int*)(block->b_call.a_args.cookie.data)); + nlmdbg_cookie2a(&block->b_call.a_args.cookie)); if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) { if (remove) { *head = block->b_next; @@ -143,14 +143,15 @@ * Find a block with a given NLM cookie. */ static inline struct nlm_block * -nlmsvc_find_block(struct nlm_cookie *cookie) +nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) { struct nlm_block *block; for (block = nlm_blocked; block; block = block->b_next) { dprintk("cookie: head of blocked queue %p, block %p\n", nlm_blocked, block); - if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)) + if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie) + && nlm_cmp_addr(sin, &block->b_host->h_addr)) break; } @@ -579,12 +580,16 @@ struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_block *block; unsigned long timeout; + struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); dprintk("lockd: GRANT_MSG RPC callback\n"); - dprintk("callback: looking for cookie %x \n", - *(unsigned int *)(call->a_args.cookie.data)); - if (!(block = nlmsvc_find_block(&call->a_args.cookie))) { - dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data)); + dprintk("callback: looking for cookie %s, host %u.%u.%u.%u\n", + nlmdbg_cookie2a(&call->a_args.cookie), + NIPQUAD(peer_addr->sin_addr.s_addr)); + if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) { + dprintk("lockd: no block for cookie %s, host %u.%u.%u.%u\n", + nlmdbg_cookie2a(&call->a_args.cookie), + NIPQUAD(peer_addr->sin_addr.s_addr)); return; } @@ -613,18 +618,21 @@ * block. */ void -nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) +nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) { struct nlm_block *block; struct nlm_file *file; - if (!(block = nlmsvc_find_block(cookie))) + dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", + *(unsigned int *)(cookie->data), + ntohl(rqstp->rq_addr.sin_addr.s_addr), status); + if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) return; file = block->b_file; file->f_count++; down(&file->f_sema); - if ((block = nlmsvc_find_block(cookie)) != NULL) { + if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); diff -urN linux-2.4.25/fs/lockd/svcproc.c linux-2.4.26/fs/lockd/svcproc.c --- linux-2.4.25/fs/lockd/svcproc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/lockd/svcproc.c 2004-04-14 06:05:40.000000000 -0700 @@ -499,7 +499,7 @@ dprintk("lockd: GRANTED_RES called\n"); - nlmsvc_grant_reply(&argp->cookie, argp->status); + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); return rpc_success; } diff -urN linux-2.4.25/fs/lockd/xdr.c linux-2.4.26/fs/lockd/xdr.c --- linux-2.4.25/fs/lockd/xdr.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/lockd/xdr.c 2004-04-14 06:05:40.000000000 -0700 @@ -55,7 +55,7 @@ c->len=4; memset(c->data, 0, 4); /* hockeypux brain damage */ } - else if(len<=8) + else if(len<=NLM_MAXCOOKIELEN) { c->len=len; memcpy(c->data, p, len); @@ -64,7 +64,7 @@ else { printk(KERN_NOTICE - "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len); + "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); return NULL; } return p; @@ -86,7 +86,7 @@ if ((len = ntohl(*p++)) != NFS2_FHSIZE) { printk(KERN_NOTICE - "lockd: bad fhandle size %x (should be %d)\n", + "lockd: bad fhandle size %d (should be %d)\n", len, NFS2_FHSIZE); return NULL; } @@ -534,7 +534,7 @@ * Buffer requirements for NLM */ #define NLM_void_sz 0 -#define NLM_cookie_sz 3 /* 1 len , 2 data */ +#define NLM_cookie_sz 1+QUADLEN(NLM_MAXCOOKIELEN) #define NLM_caller_sz 1+QUADLEN(sizeof(system_utsname.nodename)) #define NLM_netobj_sz 1+QUADLEN(XDR_MAX_NETOBJ) /* #define NLM_owner_sz 1+QUADLEN(NLM_MAXOWNER) */ @@ -643,3 +643,32 @@ } #endif +#ifdef RPC_DEBUG +const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) +{ + /* + * We can get away with a static buffer because we're only + * called with BKL held. + */ + static char buf[2*NLM_MAXCOOKIELEN+1]; + int i; + int len = sizeof(buf); + char *p = buf; + + len--; /* allow for trailing \0 */ + if (len < 3) + return "???"; + for (i = 0 ; i < cookie->len ; i++) { + if (len < 2) { + strcpy(p-3, "..."); + break; + } + sprintf(p, "%02x", cookie->data[i]); + p += 2; + len -= 2; + } + *p = '\0'; + + return buf; +} +#endif diff -urN linux-2.4.25/fs/lockd/xdr4.c linux-2.4.26/fs/lockd/xdr4.c --- linux-2.4.25/fs/lockd/xdr4.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/lockd/xdr4.c 2004-04-14 06:05:40.000000000 -0700 @@ -56,7 +56,7 @@ c->len=4; memset(c->data, 0, 4); /* hockeypux brain damage */ } - else if(len<=8) + else if(len<=NLM_MAXCOOKIELEN) { c->len=len; memcpy(c->data, p, len); @@ -65,7 +65,7 @@ else { printk(KERN_NOTICE - "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len); + "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); return NULL; } return p; @@ -540,7 +540,7 @@ * Buffer requirements for NLM */ #define NLM4_void_sz 0 -#define NLM4_cookie_sz 3 /* 1 len , 2 data */ +#define NLM4_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) #define NLM4_caller_sz 1+XDR_QUADLEN(NLM_MAXSTRLEN) #define NLM4_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) /* #define NLM4_owner_sz 1+XDR_QUADLEN(NLM4_MAXOWNER) */ diff -urN linux-2.4.25/fs/locks.c linux-2.4.26/fs/locks.c --- linux-2.4.25/fs/locks.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/locks.c 2004-04-14 06:05:40.000000000 -0700 @@ -1740,7 +1740,14 @@ before = &inode->i_flock; while ((fl = *before) != NULL) { if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) { + struct file *filp = fl->fl_file; + /* Note: locks_unlock_delete() can sleep, and + * so we may race with the call to sys_close() + * by the thread that actually owns this filp. + */ + get_file(filp); locks_unlock_delete(before); + fput(filp); before = &inode->i_flock; continue; } diff -urN linux-2.4.25/fs/nfs/dir.c linux-2.4.26/fs/nfs/dir.c --- linux-2.4.25/fs/nfs/dir.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/nfs/dir.c 2004-04-14 06:05:40.000000000 -0700 @@ -545,6 +545,11 @@ /* Unhash it, so that ->d_iput() would be called */ return 1; } + if (!(dentry->d_sb->s_flags & MS_ACTIVE)) { + /* Unhash it, so that ancestors of killed async unlink + * files will be cleaned up during umount */ + return 1; + } return 0; } @@ -1065,6 +1070,7 @@ nfs_zap_caches(new_dir); nfs_zap_caches(old_dir); + NFS_CACHEINV(old_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); out: diff -urN linux-2.4.25/fs/nfs/file.c linux-2.4.26/fs/nfs/file.c --- linux-2.4.25/fs/nfs/file.c 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/fs/nfs/file.c 2004-04-14 06:05:40.000000000 -0700 @@ -81,7 +81,7 @@ if (file->f_mode & FMODE_READ) nfs_pagein_inode(inode, 0, 0); - status = nfs_wb_file(inode, file); + status = nfs_wb_all(inode); if (!status) { status = file->f_error; file->f_error = 0; @@ -136,7 +136,7 @@ dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino); lock_kernel(); - status = nfs_wb_file(inode, file); + status = nfs_wb_all(inode); if (!status) { status = file->f_error; file->f_error = 0; @@ -241,6 +241,93 @@ goto out; } +static int +do_getlk(struct inode *inode, int cmd, struct file_lock *fl) +{ + int status; + + lock_kernel(); + status = nlmclnt_proc(inode, cmd, fl); + unlock_kernel(); + return status; +} + +static int +do_unlk(struct inode *inode, int cmd, struct file_lock *fl) +{ + sigset_t oldset; + int status; + + rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset); + /* + * Flush all pending writes before doing anything + * with locks.. + */ + filemap_fdatasync(inode->i_mapping); + down(&inode->i_sem); + nfs_wb_all(inode); + up(&inode->i_sem); + filemap_fdatawait(inode->i_mapping); + + /* NOTE: special case + * If we're signalled while cleaning up locks on process exit, we + * still need to complete the unlock. + */ + lock_kernel(); + status = nlmclnt_proc(inode, cmd, fl); + unlock_kernel(); + rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); + return status; +} + +static int +do_setlk(struct file *filp, int cmd, struct file_lock *fl) +{ + struct inode *inode = filp->f_dentry->d_inode; + int status; + + /* + * Flush all pending writes before doing anything + * with locks.. + */ + status = filemap_fdatasync(inode->i_mapping); + if (status == 0) { + down(&inode->i_sem); + status = nfs_wb_all(inode); + up(&inode->i_sem); + if (status == 0) + status = filemap_fdatawait(inode->i_mapping); + } + if (status < 0) + return status; + + lock_kernel(); + status = nlmclnt_proc(inode, cmd, fl); + /* If we were signalled we still need to ensure that + * we clean up any state on the server. We therefore + * record the lock call as having succeeded in order to + * ensure that locks_remove_posix() cleans it out when + * the process exits. + */ + if (status == -EINTR || status == -ERESTARTSYS) + posix_lock_file(filp, fl, 0); + unlock_kernel(); + if (status < 0) + return status; + + /* + * Make sure we clear the cache whenever we try to get the lock. + * This makes locking act as a cache coherency point. + */ + filemap_fdatasync(inode->i_mapping); + down(&inode->i_sem); + nfs_wb_all(inode); /* we may have slept */ + up(&inode->i_sem); + filemap_fdatawait(inode->i_mapping); + nfs_zap_caches(inode); + return 0; +} + /* * Lock a (portion of) a file */ @@ -248,8 +335,6 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl) { struct inode * inode = filp->f_dentry->d_inode; - int status = 0; - int status2; dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", inode->i_dev, inode->i_ino, @@ -266,8 +351,8 @@ /* Fake OK code if mounted without NLM support */ if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) { if (IS_GETLK(cmd)) - status = LOCK_USE_CLNT; - goto out_ok; + return LOCK_USE_CLNT; + return 0; } /* @@ -280,42 +365,9 @@ if (!fl->fl_owner || (fl->fl_flags & (FL_POSIX|FL_BROKEN)) != FL_POSIX) return -ENOLCK; - /* - * Flush all pending writes before doing anything - * with locks.. - */ - status = filemap_fdatasync(inode->i_mapping); - down(&inode->i_sem); - status2 = nfs_wb_all(inode); - if (status2 && !status) - status = status2; - up(&inode->i_sem); - status2 = filemap_fdatawait(inode->i_mapping); - if (status2 && !status) - status = status2; - if (status < 0) - return status; - - lock_kernel(); - status = nlmclnt_proc(inode, cmd, fl); - unlock_kernel(); - if (status < 0) - return status; - - status = 0; - - /* - * Make sure we clear the cache whenever we try to get the lock. - * This makes locking act as a cache coherency point. - */ - out_ok: - if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { - filemap_fdatasync(inode->i_mapping); - down(&inode->i_sem); - nfs_wb_all(inode); /* we may have slept */ - up(&inode->i_sem); - filemap_fdatawait(inode->i_mapping); - nfs_zap_caches(inode); - } - return status; + if (IS_GETLK(cmd)) + return do_getlk(inode, cmd, fl); + if (fl->fl_type == F_UNLCK) + return do_unlk(inode, cmd, fl); + return do_setlk(filp, cmd, fl); } diff -urN linux-2.4.25/fs/nfs/inode.c linux-2.4.26/fs/nfs/inode.c --- linux-2.4.25/fs/nfs/inode.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/fs/nfs/inode.c 2004-04-14 06:05:40.000000000 -0700 @@ -121,7 +121,7 @@ { int flags = sync ? FLUSH_WAIT : 0; - nfs_sync_file(inode, NULL, 0, 0, flags); + nfs_sync_file(inode, 0, 0, flags); } static void diff -urN linux-2.4.25/fs/nfs/pagelist.c linux-2.4.26/fs/nfs/pagelist.c --- linux-2.4.25/fs/nfs/pagelist.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.26/fs/nfs/pagelist.c 2004-04-14 06:05:40.000000000 -0700 @@ -364,7 +364,6 @@ * nfs_scan_list - Scan a list for matching requests * @head: One of the NFS inode request lists * @dst: Destination list - * @file: if set, ensure we match requests from this file * @idx_start: lower bound of page->index to scan * @npages: idx_start + npages sets the upper bound to scan. * @@ -376,7 +375,6 @@ */ int nfs_scan_list(struct list_head *head, struct list_head *dst, - struct file *file, unsigned long idx_start, unsigned int npages) { struct list_head *pos, *tmp; @@ -395,9 +393,6 @@ req = nfs_list_entry(pos); - if (file && req->wb_file != file) - continue; - pg_idx = page_index(req->wb_page); if (pg_idx < idx_start) continue; diff -urN linux-2.4.25/fs/nfs/read.c linux-2.4.26/fs/nfs/read.c --- linux-2.4.25/fs/nfs/read.c 2003-06-13 07:51:37.000000000 -0700 +++ linux-2.4.26/fs/nfs/read.c 2004-04-14 06:05:40.000000000 -0700 @@ -371,7 +371,7 @@ nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { int res; - res = nfs_scan_list(&inode->u.nfs_i.read, dst, NULL, idx_start, npages); + res = nfs_scan_list(&inode->u.nfs_i.read, dst, idx_start, npages); inode->u.nfs_i.nread -= res; if ((inode->u.nfs_i.nread == 0) != list_empty(&inode->u.nfs_i.read)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n"); diff -urN linux-2.4.25/fs/nfs/write.c linux-2.4.26/fs/nfs/write.c --- linux-2.4.25/fs/nfs/write.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/fs/nfs/write.c 2004-04-14 06:05:40.000000000 -0700 @@ -445,7 +445,7 @@ * Interruptible by signals only if mounted with intr flag. */ static int -nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) { struct list_head *p, *head; unsigned long idx_end; @@ -464,9 +464,6 @@ unsigned long pg_idx; struct nfs_page *req = nfs_inode_wb_entry(p); - if (file && req->wb_file != file) - continue; - pg_idx = page_index(req->wb_page); if (pg_idx < idx_start) break; @@ -538,7 +535,6 @@ * nfs_scan_dirty - Scan an inode for dirty requests * @inode: NFS inode to scan * @dst: destination list - * @file: if set, ensure we match requests from this file * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * @@ -546,10 +542,10 @@ * The requests are *not* checked to ensure that they form a contiguous set. */ static int -nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { int res; - res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages); + res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, idx_start, npages); inode->u.nfs_i.ndirty -= res; if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); @@ -577,7 +573,7 @@ npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1); if (npages) { inode = nfs_list_entry(dst->next)->wb_inode; - npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0); + npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, 0, 0); inode->u.nfs_i.ncommit -= npages; } return npages; @@ -604,7 +600,7 @@ npages = nfs_scan_lru(&server->lru_commit, dst, 1); if (npages) { inode = nfs_list_entry(dst->next)->wb_inode; - npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, NULL, 0, 0); + npages += nfs_scan_list(&inode->u.nfs_i.commit, dst, 0, 0); inode->u.nfs_i.ncommit -= npages; } return npages; @@ -614,7 +610,6 @@ * nfs_scan_commit - Scan an inode for commit requests * @inode: NFS inode to scan * @dst: destination list - * @file: if set, ensure we collect requests from this file only. * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * @@ -622,10 +617,10 @@ * The requests are *not* checked to ensure that they form a contiguous set. */ static int -nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { int res; - res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages); + res = nfs_scan_list(&inode->u.nfs_i.commit, dst, idx_start, npages); inode->u.nfs_i.ncommit -= res; if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); @@ -753,12 +748,12 @@ #ifdef CONFIG_NFS_V3 if (NFS_PROTO(inode)->version == 2) { if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); + nfs_flush_file(inode, 0, 0, 0); } else if (dirty >= wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); + nfs_flush_file(inode, 0, 0, 0); #else if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); + nfs_flush_file(inode, 0, 0, 0); #endif } @@ -1250,7 +1245,7 @@ } #endif -int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start, +int nfs_flush_file(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { LIST_HEAD(head); @@ -1258,7 +1253,7 @@ error = 0; spin_lock(&nfs_wreq_lock); - res = nfs_scan_dirty(inode, &head, file, idx_start, npages); + res = nfs_scan_dirty(inode, &head, idx_start, npages); spin_unlock(&nfs_wreq_lock); if (res) error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); @@ -1268,15 +1263,14 @@ } #ifdef CONFIG_NFS_V3 -int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start, - unsigned int npages, int how) +int nfs_commit_file(struct inode *inode, int how) { LIST_HEAD(head); int res, error = 0; spin_lock(&nfs_wreq_lock); - res = nfs_scan_commit(inode, &head, file, idx_start, npages); + res = nfs_scan_commit(inode, &head, 0, 0); spin_unlock(&nfs_wreq_lock); if (res) error = nfs_commit_list(&head, how); @@ -1286,7 +1280,7 @@ } #endif -int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start, +int nfs_sync_file(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { int error, @@ -1295,18 +1289,15 @@ wait = how & FLUSH_WAIT; how &= ~FLUSH_WAIT; - if (!inode && file) - inode = file->f_dentry->d_inode; - do { error = 0; if (wait) - error = nfs_wait_on_requests(inode, file, idx_start, npages); + error = nfs_wait_on_requests(inode, idx_start, npages); if (error == 0) - error = nfs_flush_file(inode, file, idx_start, npages, how); + error = nfs_flush_file(inode, idx_start, npages, how); #ifdef CONFIG_NFS_V3 if (error == 0) - error = nfs_commit_file(inode, file, idx_start, npages, how); + error = nfs_commit_file(inode, how); #endif } while (error > 0); return error; diff -urN linux-2.4.25/fs/smbfs/proc.c linux-2.4.26/fs/smbfs/proc.c --- linux-2.4.25/fs/smbfs/proc.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/smbfs/proc.c 2004-04-14 06:05:40.000000000 -0700 @@ -915,7 +915,9 @@ SB_of(server)->s_maxbytes = ~0ULL >> 1; VERBOSE("LFS enabled\n"); } -#ifdef CONFIG_SMB_UNIX +#ifndef CONFIG_SMB_UNIX + server->opt.capabilities &= ~SMB_CAP_UNIX; +#endif if (server->opt.capabilities & SMB_CAP_UNIX) { struct inode *inode; VERBOSE("Using UNIX CIFS extensions\n"); @@ -924,9 +926,6 @@ if (inode) inode->i_op = &smb_dir_inode_operations_unix; } -#else - server->opt.capabilities &= ~SMB_CAP_UNIX; -#endif VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n", server->opt.protocol, server->opt.max_xmit, server->conn_pid, @@ -2615,9 +2614,18 @@ struct inode *inode = dir->d_inode; int result; +retry: result = smb_proc_getattr_trans2_std(server, dir, attr); - if (result < 0) + if (result < 0) { + if (server->rcls == ERRSRV && server->err == ERRerror) { + /* a damn Win95 bug - sometimes it clags if you + ask it too fast */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/5); + goto retry; + } goto out; + } /* * None of the other getattr versions here can make win9x diff -urN linux-2.4.25/fs/xfs/Makefile linux-2.4.26/fs/xfs/Makefile --- linux-2.4.25/fs/xfs/Makefile 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/Makefile 2004-04-14 06:05:40.000000000 -0700 @@ -108,7 +108,9 @@ xfs_vfsops.o \ xfs_vnodeops.o \ xfs_refcache.o \ - xfs_rw.o + xfs_rw.o \ + xfs_dmops.o \ + xfs_qmops.o # Objects not built in this directory obj-y += linux/linux_xfs.o \ @@ -119,15 +121,11 @@ ifeq ($(CONFIG_XFS_DMAPI),y) subdir-$(CONFIG_XFS_FS) += dmapi obj-y += dmapi/xfs_dmapi.o -else - obj-y += xfs_dmops.o endif ifeq ($(CONFIG_XFS_QUOTA),y) subdir-$(CONFIG_XFS_FS) += quota obj-y += quota/xfs_quota.o -else - obj-y += xfs_qmops.o endif include $(TOPDIR)/Rules.make diff -urN linux-2.4.25/fs/xfs/linux/kmem.h linux-2.4.26/fs/xfs/linux/kmem.h --- linux-2.4.25/fs/xfs/linux/kmem.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/kmem.h 2004-04-14 06:05:40.000000000 -0700 @@ -59,6 +59,12 @@ current->flags |= PF_FSTRANS; \ } while (0) +#define PFLAGS_CLEAR_FSTRANS(STATEP) do { \ + *(STATEP) = current->flags; \ + current->flags &= ~PF_FSTRANS; \ +} while (0) + + #define PFLAGS_RESTORE(STATEP) do { \ current->flags = *(STATEP); \ } while (0) diff -urN linux-2.4.25/fs/xfs/linux/xfs_aops.c linux-2.4.26/fs/xfs/linux/xfs_aops.c --- linux-2.4.25/fs/xfs/linux/xfs_aops.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_aops.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -54,8 +54,54 @@ #include "xfs_iomap.h" #include -STATIC void convert_page(struct inode *, struct page *, - xfs_iomap_t *, void *, int, int); +STATIC void xfs_count_page_state(struct page *, int *, int *, int *); +STATIC void xfs_convert_page(struct inode *, struct page *, + xfs_iomap_t *, void *, int, int); + +#if defined(XFS_RW_TRACE) +void +xfs_page_trace( + int tag, + struct inode *inode, + struct page *page, + int mask) +{ + xfs_inode_t *ip; + bhv_desc_t *bdp; + vnode_t *vp = LINVFS_GET_VP(inode); + loff_t isize = i_size_read(inode); + loff_t offset = page->index << PAGE_CACHE_SHIFT; + int delalloc = -1, unmapped = -1, unwritten = -1; + + if (page_has_buffers(page)) + xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); + + bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); + ip = XFS_BHVTOI(bdp); + if (!ip->i_rwtrace) + return; + + ktrace_enter(ip->i_rwtrace, + (void *)((unsigned long)tag), + (void *)ip, + (void *)inode, + (void *)page, + (void *)((unsigned long)mask), + (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), + (void *)((unsigned long)((isize >> 32) & 0xffffffff)), + (void *)((unsigned long)(isize & 0xffffffff)), + (void *)((unsigned long)((offset >> 32) & 0xffffffff)), + (void *)((unsigned long)(offset & 0xffffffff)), + (void *)((unsigned long)delalloc), + (void *)((unsigned long)unmapped), + (void *)((unsigned long)unwritten), + (void *)NULL, + (void *)NULL); +} +#else +#define xfs_page_trace(tag, inode, page, mask) +#endif void linvfs_unwritten_done( @@ -97,7 +143,7 @@ } STATIC int -map_blocks( +xfs_map_blocks( struct inode *inode, loff_t offset, ssize_t count, @@ -127,12 +173,11 @@ } /* - * match_offset_to_mapping * Finds the corresponding mapping in block @map array of the * given @offset within a @page. */ STATIC xfs_iomap_t * -match_offset_to_mapping( +xfs_offset_to_map( struct page *page, xfs_iomap_t *iomapp, unsigned long offset) @@ -153,7 +198,7 @@ } STATIC void -map_buffer_at_offset( +xfs_map_at_offset( struct page *page, struct buffer_head *bh, unsigned long offset, @@ -194,7 +239,7 @@ * in units of filesystem blocks. */ STATIC struct page * -probe_unwritten_page( +xfs_probe_unwritten_page( struct address_space *mapping, unsigned long index, xfs_iomap_t *iomapp, @@ -218,11 +263,11 @@ do { if (!buffer_unwritten(bh)) break; - if (!match_offset_to_mapping(page, iomapp, p_offset)) + if (!xfs_offset_to_map(page, iomapp, p_offset)) break; if (p_offset >= max_offset) break; - map_buffer_at_offset(page, bh, p_offset, bbits, iomapp); + xfs_map_at_offset(page, bh, p_offset, bbits, iomapp); set_buffer_unwritten_io(bh); bh->b_private = pb; p_offset += bh->b_size; @@ -242,7 +287,7 @@ * yet - clustering for mmap write case. */ STATIC unsigned int -probe_unmapped_page( +xfs_probe_unmapped_page( struct address_space *mapping, unsigned long index, unsigned int pg_offset) @@ -275,7 +320,7 @@ } STATIC unsigned int -probe_unmapped_cluster( +xfs_probe_unmapped_cluster( struct inode *inode, struct page *startpage, struct buffer_head *bh, @@ -300,7 +345,7 @@ /* Prune this back to avoid pathological behavior */ tloff = min(tlast, startpage->index + 64); for (tindex = startpage->index + 1; tindex < tloff; tindex++) { - len = probe_unmapped_page(mapping, tindex, + len = xfs_probe_unmapped_page(mapping, tindex, PAGE_CACHE_SIZE); if (!len) return total; @@ -308,7 +353,8 @@ } if (tindex == tlast && (tloff = i_size_read(inode) & (PAGE_CACHE_SIZE - 1))) { - total += probe_unmapped_page(mapping, tindex, tloff); + total += xfs_probe_unmapped_page(mapping, + tindex, tloff); } } return total; @@ -320,7 +366,7 @@ * reference count. */ STATIC struct page * -probe_delalloc_page( +xfs_probe_delalloc_page( struct inode *inode, unsigned long index) { @@ -353,7 +399,7 @@ } STATIC int -map_unwritten( +xfs_map_unwritten( struct inode *inode, struct page *start_page, struct buffer_head *head, @@ -401,22 +447,16 @@ do { if (!buffer_unwritten(bh)) break; - tmp = match_offset_to_mapping(start_page, iomapp, p_offset); + tmp = xfs_offset_to_map(start_page, iomapp, p_offset); if (!tmp) break; - map_buffer_at_offset(start_page, bh, p_offset, block_bits, iomapp); + xfs_map_at_offset(start_page, bh, p_offset, block_bits, iomapp); set_buffer_unwritten_io(bh); bh->b_private = pb; p_offset += bh->b_size; nblocks++; } while ((bh = bh->b_this_page) != head); - if (unlikely(nblocks == 0)) { - printk("XFS: bad unwritten extent map: bh=0x%p, iomapp=0x%p\n", - curr, iomapp); - BUG(); - } - atomic_add(nblocks, &pb->pb_io_remaining); /* If we reached the end of the page, map forwards in any @@ -432,13 +472,15 @@ tloff = (iomapp->iomap_offset + iomapp->iomap_bsize) >> PAGE_CACHE_SHIFT; tloff = min(tlast, tloff); for (tindex = start_page->index + 1; tindex < tloff; tindex++) { - page = probe_unwritten_page(mapping, tindex, iomapp, pb, + page = xfs_probe_unwritten_page(mapping, + tindex, iomapp, pb, PAGE_CACHE_SIZE, &bs, bbits); if (!page) break; nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); - convert_page(inode, page, iomapp, pb, startio, all_bh); + xfs_convert_page(inode, page, iomapp, pb, + startio, all_bh); /* stop if converting the next page might add * enough blocks that the corresponding byte * count won't fit in our ulong page buf length */ @@ -448,12 +490,14 @@ if (tindex == tlast && (tloff = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)))) { - page = probe_unwritten_page(mapping, tindex, iomapp, pb, + page = xfs_probe_unwritten_page(mapping, + tindex, iomapp, pb, tloff, &bs, bbits); if (page) { nblocks += bs; atomic_add(bs, &pb->pb_io_remaining); - convert_page(inode, page, iomapp, pb, startio, all_bh); + xfs_convert_page(inode, page, iomapp, pb, + startio, all_bh); if (nblocks >= ((ULONG_MAX - PAGE_SIZE) >> block_bits)) goto enough; } @@ -480,7 +524,7 @@ } STATIC void -submit_page( +xfs_submit_page( struct page *page, struct buffer_head *bh_arr[], int cnt) @@ -498,8 +542,10 @@ clear_buffer_dirty(bh); } - for (i = 0; i < cnt; i++) + for (i = 0; i < cnt; i++) { + refile_buffer(bh_arr[i]); submit_bh(WRITE, bh_arr[i]); + } } else unlock_page(page); } @@ -511,7 +557,7 @@ * that the page has no mapping at all. */ STATIC void -convert_page( +xfs_convert_page( struct inode *inode, struct page *page, xfs_iomap_t *iomapp, @@ -544,7 +590,7 @@ } continue; } - tmp = match_offset_to_mapping(page, mp, offset); + tmp = xfs_offset_to_map(page, mp, offset); if (!tmp) continue; ASSERT(!(tmp->iomap_flags & IOMAP_HOLE)); @@ -556,10 +602,10 @@ */ if (buffer_unwritten(bh) && !bh->b_end_io) { ASSERT(tmp->iomap_flags & IOMAP_UNWRITTEN); - map_unwritten(inode, page, head, bh, + xfs_map_unwritten(inode, page, head, bh, offset, bbits, tmp, startio, all_bh); } else if (! (buffer_unwritten(bh) && buffer_locked(bh))) { - map_buffer_at_offset(page, bh, offset, bbits, tmp); + xfs_map_at_offset(page, bh, offset, bbits, tmp); if (buffer_unwritten(bh)) { set_buffer_unwritten_io(bh); bh->b_private = private; @@ -575,7 +621,7 @@ } while (i++, (bh = bh->b_this_page) != head); if (startio) { - submit_page(page, bh_arr, index); + xfs_submit_page(page, bh_arr, index); } else { unlock_page(page); } @@ -586,7 +632,7 @@ * by mp and following the start page. */ STATIC void -cluster_write( +xfs_cluster_write( struct inode *inode, unsigned long tindex, xfs_iomap_t *iomapp, @@ -598,10 +644,10 @@ tlast = (iomapp->iomap_offset + iomapp->iomap_bsize) >> PAGE_CACHE_SHIFT; for (; tindex < tlast; tindex++) { - page = probe_delalloc_page(inode, tindex); + page = xfs_probe_delalloc_page(inode, tindex); if (!page) break; - convert_page(inode, page, iomapp, NULL, startio, all_bh); + xfs_convert_page(inode, page, iomapp, NULL, startio, all_bh); } } @@ -625,7 +671,7 @@ */ STATIC int -page_state_convert( +xfs_page_state_convert( struct inode *inode, struct page *page, int startio, @@ -634,7 +680,8 @@ struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; xfs_iomap_t *iomp, iomap; unsigned long p_offset = 0, end_index; - loff_t offset, end_offset; + loff_t offset; + unsigned long long end_offset; int len, err, i, cnt = 0, uptodate = 1; int flags = startio ? 0 : BMAPI_TRYLOCK; int page_dirty = 1; @@ -651,9 +698,8 @@ } offset = (loff_t)page->index << PAGE_CACHE_SHIFT; - end_offset = offset + PAGE_CACHE_SIZE; - if (end_offset > i_size_read(inode)) - end_offset = i_size_read(inode); + end_offset = min_t(unsigned long long, + offset + PAGE_CACHE_SIZE, i_size_read(inode)); bh = head = page_buffers(page); iomp = NULL; @@ -668,7 +714,7 @@ continue; if (iomp) { - iomp = match_offset_to_mapping(page, &iomap, p_offset); + iomp = xfs_offset_to_map(page, &iomap, p_offset); } /* @@ -677,17 +723,17 @@ */ if (buffer_unwritten(bh)) { if (!iomp) { - err = map_blocks(inode, offset, len, &iomap, + err = xfs_map_blocks(inode, offset, len, &iomap, BMAPI_READ|BMAPI_IGNSTATE); if (err) { goto error; } - iomp = match_offset_to_mapping(page, &iomap, + iomp = xfs_offset_to_map(page, &iomap, p_offset); } - if (iomp) { + if (iomp && startio) { if (!bh->b_end_io) { - err = map_unwritten(inode, page, + err = xfs_map_unwritten(inode, page, head, bh, p_offset, inode->i_blkbits, iomp, startio, unmapped); @@ -695,12 +741,7 @@ goto error; } } - if (startio) { - bh_arr[cnt++] = bh; - } else { - unlock_buffer(bh); - mark_buffer_dirty(bh); - } + bh_arr[cnt++] = bh; page_dirty = 0; } /* @@ -709,17 +750,17 @@ */ } else if (buffer_delay(bh)) { if (!iomp) { - err = map_blocks(inode, offset, len, &iomap, - BMAPI_ALLOCATE | flags); + err = xfs_map_blocks(inode, offset, len, &iomap, + BMAPI_ALLOCATE | flags); if (err) { goto error; } - iomp = match_offset_to_mapping(page, &iomap, + iomp = xfs_offset_to_map(page, &iomap, p_offset); } if (iomp) { - map_buffer_at_offset(page, bh, p_offset, - inode->i_blkbits, iomp); + xfs_map_at_offset(page, bh, p_offset, + inode->i_blkbits, iomp); if (startio) { bh_arr[cnt++] = bh; } else { @@ -740,19 +781,19 @@ * need to write the whole page out. */ if (!iomp) { - size = probe_unmapped_cluster( + size = xfs_probe_unmapped_cluster( inode, page, bh, head); - err = map_blocks(inode, offset, - size, &iomap, - BMAPI_WRITE | BMAPI_MMAP); + err = xfs_map_blocks(inode, offset, + size, &iomap, + BMAPI_WRITE|BMAPI_MMAP); if (err) { goto error; } - iomp = match_offset_to_mapping(page, &iomap, + iomp = xfs_offset_to_map(page, &iomap, p_offset); } if (iomp) { - map_buffer_at_offset(page, + xfs_map_at_offset(page, bh, p_offset, inode->i_blkbits, iomp); if (startio) { @@ -778,10 +819,10 @@ SetPageUptodate(page); if (startio) - submit_page(page, bh_arr, cnt); + xfs_submit_page(page, bh_arr, cnt); if (iomp) - cluster_write(inode, page->index + 1, iomp, startio, unmapped); + xfs_cluster_write(inode, page->index + 1, iomp, startio, unmapped); return page_dirty; @@ -841,9 +882,9 @@ loff_t delta; /* For unwritten extents do not report a disk address on - * the read case. + * the read case (treat as if we're reading into a hole). */ - if (create || ((iomap.iomap_flags & IOMAP_UNWRITTEN) == 0)) { + if (create || !(iomap.iomap_flags & IOMAP_UNWRITTEN)) { delta = offset - iomap.iomap_offset; delta >>= inode->i_blkbits; @@ -853,10 +894,7 @@ bh_result->b_blocknr = bn; set_buffer_mapped(bh_result); } - if (iomap.iomap_flags & IOMAP_UNWRITTEN) { - if (create) { - set_buffer_mapped(bh_result); - } + if (create && (iomap.iomap_flags & IOMAP_UNWRITTEN)) { set_buffer_unwritten(bh_result); set_buffer_delay(bh_result); } @@ -946,7 +984,7 @@ } STATIC void -count_page_state( +xfs_count_page_state( struct page *page, int *delalloc, int *unmapped, @@ -998,13 +1036,15 @@ int need_trans; int delalloc, unmapped, unwritten; struct inode *inode = page->mapping->host; - xfs_pflags_t pflags; + xfs_pflags_t pflags; + + xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0); /* * We need a transaction if: * 1. There are delalloc buffers on the page - * 2. The page is upto date and we have unmapped buffers - * 3. The page is upto date and we have no buffers + * 2. The page is uptodate and we have unmapped buffers + * 3. The page is uptodate and we have no buffers * 4. There are unwritten buffers on the page */ @@ -1012,7 +1052,7 @@ unmapped = 1; need_trans = 1; } else { - count_page_state(page, &delalloc, &unmapped, &unwritten); + xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); if (!PageUptodate(page)) unmapped = 0; need_trans = delalloc + unmapped + unwritten; @@ -1041,7 +1081,7 @@ */ if (need_trans) PFLAGS_SET_NOIO(&pflags); - error = page_state_convert(inode, page, 1, unmapped); + error = xfs_page_state_convert(inode, page, 1, unmapped); if (need_trans) PFLAGS_RESTORE(&pflags); if (error == -EAGAIN) @@ -1085,22 +1125,31 @@ int gfp_mask) { struct inode *inode = page->mapping->host; - int delalloc, unmapped, unwritten; + int dirty, delalloc, unmapped, unwritten; + + xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask); - count_page_state(page, &delalloc, &unmapped, &unwritten); + xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); if (!delalloc && !unwritten) return 1; if (!(gfp_mask & __GFP_FS)) return 0; + /* If we are already inside a transaction or the thread cannot + * do I/O, we cannot release this page. + */ + if (PFLAGS_TEST_FSTRANS() || PFLAGS_TEST_NOIO()) + return 0; + /* * Convert delalloc space to real space, do not flush the * data out to disk, that will be done by the caller. * Never need to allocate space here - we will always * come back to writepage in that case. */ - return (page_state_convert(inode, page, 0, 0) == 0) ? 1 : 0; + dirty = xfs_page_state_convert(inode, page, 0, 0); + return (dirty == 0 && !unwritten) ? 1 : 0; } STATIC int @@ -1155,7 +1204,7 @@ map_flags = (rw ? BMAPI_WRITE : BMAPI_READ) | BMAPI_DIRECT; pb_flags = (rw ? PBF_WRITE : PBF_READ) | PBF_FORCEIO | PBF_DIRECTIO; while (length) { - error = map_blocks(inode, offset, length, &iomap, map_flags); + error = xfs_map_blocks(inode, offset, length, &iomap, map_flags); if (error) break; BUG_ON(iomap.iomap_flags & IOMAP_DELAY); diff -urN linux-2.4.25/fs/xfs/linux/xfs_buf.c linux-2.4.26/fs/xfs/linux/xfs_buf.c --- linux-2.4.25/fs/xfs/linux/xfs_buf.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_buf.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -56,18 +56,8 @@ #include #include -#include -#include -#include "kmem.h" - -#include "xfs_types.h" -#include "xfs_cred.h" -#include "xfs_lrw.h" -#include "xfs_buf.h" - -#define NBBY 8 -#define BBSHIFT 9 -#define BBMASK ((1 << BBSHIFT) - 1) +#include "xfs_linux.h" + #define BN_ALIGN_MASK ((1 << (PAGE_CACHE_SHIFT - BBSHIFT)) - 1) #ifndef GFP_READAHEAD @@ -128,63 +118,12 @@ struct buffer_head *pb_resv_bh = NULL; /* list of bh */ int pb_resv_bh_cnt = 0; /* # of bh available */ -STATIC void pagebuf_daemon_wakeup(int); +STATIC void pagebuf_daemon_wakeup(void); STATIC void _pagebuf_ioapply(page_buf_t *); STATIC void pagebuf_delwri_queue(page_buf_t *, int); STATIC void pagebuf_runall_queues(struct list_head[]); /* - * Pagebuf module configuration parameters, exported via - * /proc/sys/vm/pagebuf - */ - -typedef struct pb_sysctl_val { - int min; - int val; - int max; -} pb_sysctl_val_t; - -struct { - pb_sysctl_val_t flush_interval; /* interval between runs of the - * delwri flush daemon. */ - pb_sysctl_val_t age_buffer; /* time for buffer to age before - * we flush it. */ - pb_sysctl_val_t stats_clear; /* clear the pagebuf stats */ - pb_sysctl_val_t debug; /* debug tracing on or off */ -} pb_params = { - /* MIN DFLT MAX */ - .flush_interval = { HZ/2, HZ, 30*HZ }, - .age_buffer = { 1*HZ, 15*HZ, 300*HZ }, - .stats_clear = { 0, 0, 1 }, - .debug = { 0, 0, 1 }, -}; - -enum { - PB_FLUSH_INT = 1, - PB_FLUSH_AGE = 2, - PB_STATS_CLEAR = 3, - PB_DEBUG = 4, -}; - -/* - * Pagebuf statistics variables - */ - -struct { - u_int32_t pb_get; - u_int32_t pb_create; - u_int32_t pb_get_locked; - u_int32_t pb_get_locked_waited; - u_int32_t pb_busy_locked; - u_int32_t pb_miss_locked; - u_int32_t pb_page_retries; - u_int32_t pb_page_found; - u_int32_t pb_get_read; -} pbstats; - -#define PB_STATS_INC(count) ( pbstats.count++ ) - -/* * Pagebuf debugging */ @@ -196,8 +135,6 @@ void *data, void *ra) { - if (!pb_params.debug.val) - return; ktrace_enter(pagebuf_trace_buf, pb, id, (void *)(unsigned long)pb->pb_flags, @@ -254,7 +191,6 @@ typedef struct { struct list_head pb_hash; - int pb_count; spinlock_t pb_hash_lock; } pb_hash_t; @@ -372,7 +308,7 @@ atomic_set(&pb->pb_pin_count, 0); init_waitqueue_head(&pb->pb_waiters); - PB_STATS_INC(pb_create); + XFS_STATS_INC(pb_create); PB_TRACE(pb, "initialize", target); } @@ -386,8 +322,6 @@ int page_count, page_buf_flags_t flags) { - int gpf_mask = pb_to_gfp(flags); - /* Make sure that we have a page list */ if (pb->pb_pages == NULL) { pb->pb_offset = page_buf_poff(pb->pb_file_offset); @@ -395,8 +329,8 @@ if (page_count <= PB_PAGES) { pb->pb_pages = pb->pb_page_array; } else { - pb->pb_pages = kmalloc(sizeof(struct page *) * - page_count, gpf_mask); + pb->pb_pages = kmem_alloc(sizeof(struct page *) * + page_count, pb_to_km(flags)); if (pb->pb_pages == NULL) return -ENOMEM; } @@ -425,53 +359,41 @@ } /* - * _pagebuf_free_object + * pagebuf_free * - * _pagebuf_free_object releases the contents specified buffer. - * The modification state of any associated pages is left unchanged. + * pagebuf_free releases the specified buffer. The modification + * state of any associated pages is left unchanged. */ void -_pagebuf_free_object( - pb_hash_t *hash, /* hash bucket for buffer */ - page_buf_t *pb) /* buffer to deallocate */ -{ - page_buf_flags_t pb_flags = pb->pb_flags; - - PB_TRACE(pb, "free_object", 0); - pb->pb_flags |= PBF_FREED; - - if (hash) { - if (!list_empty(&pb->pb_hash_list)) { - hash->pb_count--; - list_del_init(&pb->pb_hash_list); - } - spin_unlock(&hash->pb_hash_lock); - } +pagebuf_free( + page_buf_t *pb) +{ + PB_TRACE(pb, "free", 0); + + ASSERT(list_empty(&pb->pb_hash_list)); - if (!(pb_flags & PBF_FREED)) { - /* release any virtual mapping */ ; - if (pb->pb_flags & _PBF_ADDR_ALLOCATED) { - void *vaddr = pagebuf_mapout_locked(pb); - if (vaddr) { - free_address(vaddr); - } + /* release any virtual mapping */ ; + if (pb->pb_flags & _PBF_ADDR_ALLOCATED) { + void *vaddr = pagebuf_mapout_locked(pb); + if (vaddr) { + free_address(vaddr); } + } - if (pb->pb_flags & _PBF_MEM_ALLOCATED) { - if (pb->pb_pages) { - /* release the pages in the address list */ - if ((pb->pb_pages[0]) && - (pb->pb_flags & _PBF_MEM_SLAB)) { - kfree(pb->pb_addr); - } else { - _pagebuf_freepages(pb); - } - if (pb->pb_pages != pb->pb_page_array) - kfree(pb->pb_pages); - pb->pb_pages = NULL; + if (pb->pb_flags & _PBF_MEM_ALLOCATED) { + if (pb->pb_pages) { + /* release the pages in the address list */ + if ((pb->pb_pages[0]) && + (pb->pb_flags & _PBF_MEM_SLAB)) { + kfree(pb->pb_addr); + } else { + _pagebuf_freepages(pb); } - pb->pb_flags &= ~(_PBF_MEM_ALLOCATED|_PBF_MEM_SLAB); + if (pb->pb_pages != pb->pb_page_array) + kfree(pb->pb_pages); + pb->pb_pages = NULL; } + pb->pb_flags &= ~(_PBF_MEM_ALLOCATED|_PBF_MEM_SLAB); } pagebuf_deallocate(pb); @@ -496,32 +418,11 @@ loff_t next_buffer_offset; unsigned long page_count, pi, index; struct page *page; - int gfp_mask, retry_count = 5, rval = 0; - int all_mapped, good_pages; + int gfp_mask = pb_to_gfp(flags); + int all_mapped, good_pages, rval, retries; size_t blocksize; - /* For pagebufs where we want to map an address, do not use - * highmem pages - so that we do not need to use kmap resources - * to access the data. - * - * For pages where the caller has indicated there may be resource - * contention (e.g. called from a transaction) do not flush - * delalloc pages to obtain memory. - */ - - if (flags & PBF_READ_AHEAD) { - gfp_mask = GFP_READAHEAD; - retry_count = 0; - } else if (flags & PBF_DONT_BLOCK) { - gfp_mask = GFP_NOFS; - } else if (flags & PBF_MAPPABLE) { - gfp_mask = GFP_KERNEL; - } else { - gfp_mask = GFP_HIGHUSER; - } - next_buffer_offset = pb->pb_file_offset + pb->pb_buffer_length; - good_pages = page_count = (page_buf_btoc(next_buffer_offset) - page_buf_btoct(pb->pb_file_offset)); @@ -532,6 +433,7 @@ } if ((flags & PBF_MAPPED) && !(pb->pb_flags & PBF_MAPPED)) { all_mapped = 1; + rval = 0; goto mapit; } return 0; @@ -549,21 +451,30 @@ index = (pb->pb_file_offset - pb->pb_offset) >> PAGE_CACHE_SHIFT; for (pi = 0; pi < page_count; pi++, index++) { if (pb->pb_pages[pi] == 0) { + retries = 0; retry: page = find_or_create_page(aspace, index, gfp_mask); if (!page) { - if (--retry_count > 0) { - PB_STATS_INC(pb_page_retries); - pagebuf_daemon_wakeup(1); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(10); - goto retry; + if (flags & PBF_READ_AHEAD) + return -ENOMEM; + /* + * This could deadlock. But until all the + * XFS lowlevel code is revamped to handle + * buffer allocation failures we can't do + * much. + */ + if (!(++retries % 100)) { + printk(KERN_ERR + "possibly deadlocking in %s\n", + __FUNCTION__); } - rval = -ENOMEM; - all_mapped = 0; - continue; + XFS_STATS_INC(pb_page_retries); + pagebuf_daemon_wakeup(); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(10); + goto retry; } - PB_STATS_INC(pb_page_found); + XFS_STATS_INC(pb_page_found); mark_page_accessed(page); pb->pb_pages[pi] = page; } else { @@ -587,6 +498,7 @@ } } + pb->pb_flags |= _PBF_PAGECACHE; mapit: pb->pb_flags |= _PBF_MEM_ALLOCATED; if (all_mapped) { @@ -780,16 +692,14 @@ list_for_each(p, &h->pb_hash) { pb = list_entry(p, page_buf_t, pb_hash_list); - if ((target == pb->pb_target) && - (pb->pb_file_offset == range_base) && - (pb->pb_buffer_length == range_length)) { - if (pb->pb_flags & PBF_FREED) - break; + if (pb->pb_target == target && + pb->pb_file_offset == range_base && + pb->pb_buffer_length == range_length) { /* If we look at something bring it to the * front of the list for next time */ - list_del(&pb->pb_hash_list); - list_add(&pb->pb_hash_list, &h->pb_hash); + atomic_inc(&pb->pb_hold); + list_move(&pb->pb_hash_list, &h->pb_hash); goto found; } } @@ -797,19 +707,17 @@ /* No match found */ if (new_pb) { _pagebuf_initialize(new_pb, target, range_base, - range_length, flags | _PBF_LOCKABLE); + range_length, flags); new_pb->pb_hash_index = hval; - h->pb_count++; list_add(&new_pb->pb_hash_list, &h->pb_hash); } else { - PB_STATS_INC(pb_miss_locked); + XFS_STATS_INC(pb_miss_locked); } spin_unlock(&h->pb_hash_lock); return (new_pb); found: - atomic_inc(&pb->pb_hold); spin_unlock(&h->pb_hash_lock); /* Attempt to get the semaphore without sleeping, @@ -822,7 +730,7 @@ /* wait for buffer ownership */ PB_TRACE(pb, "get_lock", 0); pagebuf_lock(pb); - PB_STATS_INC(pb_get_locked_waited); + XFS_STATS_INC(pb_get_locked_waited); } else { /* We asked for a trylock and failed, no need * to look at file offset and length here, we @@ -832,7 +740,7 @@ */ pagebuf_rele(pb); - PB_STATS_INC(pb_busy_locked); + XFS_STATS_INC(pb_busy_locked); return (NULL); } } else { @@ -841,15 +749,13 @@ } if (pb->pb_flags & PBF_STALE) - pb->pb_flags &= PBF_MAPPABLE | \ - PBF_MAPPED | \ - _PBF_LOCKABLE | \ + pb->pb_flags &= PBF_MAPPED | \ _PBF_ALL_PAGES_MAPPED | \ _PBF_ADDR_ALLOCATED | \ _PBF_MEM_ALLOCATED | \ _PBF_MEM_SLAB; PB_TRACE(pb, "got_lock", 0); - PB_STATS_INC(pb_get_locked); + XFS_STATS_INC(pb_get_locked); return (pb); } @@ -905,13 +811,14 @@ return (NULL); } - PB_STATS_INC(pb_get); + XFS_STATS_INC(pb_get); /* fill in any missing pages */ error = _pagebuf_lookup_pages(pb, pb->pb_target->pbr_mapping, flags); if (unlikely(error)) { - pagebuf_free(pb); - return (NULL); + printk(KERN_WARNING + "pagebuf_get: warning, failed to lookup pages\n"); + goto no_buffer; } /* @@ -924,7 +831,7 @@ if (flags & PBF_READ) { if (PBF_NOT_DONE(pb)) { PB_TRACE(pb, "get_read", (unsigned long)flags); - PB_STATS_INC(pb_get_read); + XFS_STATS_INC(pb_get_read); pagebuf_iostart(pb, flags); } else if (flags & PBF_ASYNC) { PB_TRACE(pb, "get_read_async", (unsigned long)flags); @@ -932,10 +839,7 @@ * Read ahead call which is already satisfied, * drop the buffer */ - if (flags & (PBF_LOCK | PBF_TRYLOCK)) - pagebuf_unlock(pb); - pagebuf_rele(pb); - return NULL; + goto no_buffer; } else { PB_TRACE(pb, "get_read_done", (unsigned long)flags); /* We do not want read in the flags */ @@ -944,7 +848,14 @@ } else { PB_TRACE(pb, "get_write", (unsigned long)flags); } - return (pb); + + return pb; + +no_buffer: + if (flags & (PBF_LOCK | PBF_TRYLOCK)) + pagebuf_unlock(pb); + pagebuf_rele(pb); + return NULL; } /* @@ -959,7 +870,7 @@ { page_buf_t *pb; - flags |= _PBF_PRIVATE_BH | _PBF_LOCKABLE; + flags |= _PBF_PRIVATE_BH; pb = pagebuf_allocate(flags); if (pb) { _pagebuf_initialize(pb, target, ioff, isize, flags); @@ -978,7 +889,7 @@ size_t isize, page_buf_flags_t flags) { - flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_MAPPABLE|PBF_READ_AHEAD); + flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_READ_AHEAD); pagebuf_get(target, ioff, isize, flags); } @@ -989,9 +900,9 @@ { page_buf_t *pb; - pb = pagebuf_allocate(_PBF_LOCKABLE); + pb = pagebuf_allocate(0); if (pb) - _pagebuf_initialize(pb, target, 0, len, _PBF_LOCKABLE); + _pagebuf_initialize(pb, target, 0, len, 0); return pb; } @@ -1065,7 +976,7 @@ { int rval; void *rmem = NULL; - page_buf_flags_t flags = _PBF_LOCKABLE | PBF_FORCEIO; + page_buf_flags_t flags = PBF_FORCEIO; page_buf_t *pb; size_t tlen = 0; @@ -1124,26 +1035,6 @@ } /* - * pagebuf_free - * - * pagebuf_free releases the specified buffer. The modification - * state of any associated pages is left unchanged. - */ -void -pagebuf_free( - page_buf_t *pb) -{ - if (pb->pb_flags & _PBF_LOCKABLE) { - pb_hash_t *h = pb_hash(pb); - - spin_lock(&h->pb_hash_lock); - _pagebuf_free_object(h, pb); - } else { - _pagebuf_free_object(NULL, pb); - } -} - -/* * pagebuf_rele * * pagebuf_rele releases a hold on the specified buffer. If the @@ -1153,44 +1044,37 @@ pagebuf_rele( page_buf_t *pb) { - pb_hash_t *h; + pb_hash_t *hash = pb_hash(pb); PB_TRACE(pb, "rele", pb->pb_relse); - if (pb->pb_flags & _PBF_LOCKABLE) { - h = pb_hash(pb); - spin_lock(&h->pb_hash_lock); - } else { - h = NULL; - } - if (atomic_dec_and_test(&pb->pb_hold)) { + if (atomic_dec_and_lock(&pb->pb_hold, &hash->pb_hash_lock)) { int do_free = 1; if (pb->pb_relse) { atomic_inc(&pb->pb_hold); - if (h) - spin_unlock(&h->pb_hash_lock); + spin_unlock(&hash->pb_hash_lock); (*(pb->pb_relse)) (pb); + spin_lock(&hash->pb_hash_lock); do_free = 0; } + if (pb->pb_flags & PBF_DELWRI) { pb->pb_flags |= PBF_ASYNC; atomic_inc(&pb->pb_hold); - if (h && do_free) - spin_unlock(&h->pb_hash_lock); pagebuf_delwri_queue(pb, 0); do_free = 0; } else if (pb->pb_flags & PBF_FS_MANAGED) { - if (h) - spin_unlock(&h->pb_hash_lock); do_free = 0; } if (do_free) { - _pagebuf_free_object(h, pb); + list_del_init(&pb->pb_hash_list); + spin_unlock(&hash->pb_hash_lock); + pagebuf_free(pb); + } else { + spin_unlock(&hash->pb_hash_lock); } - } else if (h) { - spin_unlock(&h->pb_hash_lock); } } @@ -1221,7 +1105,6 @@ { int locked; - ASSERT(pb->pb_flags & _PBF_LOCKABLE); locked = down_trylock(&pb->pb_sema) == 0; if (locked) { PB_SET_OWNER(pb); @@ -1239,7 +1122,6 @@ pagebuf_lock_value( page_buf_t *pb) { - ASSERT(pb->pb_flags & _PBF_LOCKABLE); return(atomic_read(&pb->pb_sema.count)); } @@ -1255,8 +1137,6 @@ pagebuf_lock( page_buf_t *pb) { - ASSERT(pb->pb_flags & _PBF_LOCKABLE); - PB_TRACE(pb, "lock", 0); if (atomic_read(&pb->pb_io_remaining)) blk_run_queues(); @@ -1277,7 +1157,6 @@ pagebuf_unlock( /* unlock buffer */ page_buf_t *pb) /* buffer to unlock */ { - ASSERT(pb->pb_flags & _PBF_LOCKABLE); PB_CLEAR_OWNER(pb); up(&pb->pb_sema); PB_TRACE(pb, "unlock", 0); @@ -1387,7 +1266,7 @@ } if (pb->pb_flags & PBF_ASYNC) { - if ((pb->pb_flags & _PBF_LOCKABLE) && !pb->pb_relse) + if (!pb->pb_relse) pagebuf_unlock(pb); pagebuf_rele(pb); } @@ -1457,7 +1336,7 @@ page_buf_t *pb, /* buffer to start */ page_buf_flags_t flags) /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ /* PBF_WRITE, PBF_DELWRI, */ - /* PBF_SYNC, PBF_DONT_BLOCK */ + /* PBF_DONT_BLOCK */ { int status = 0; @@ -1465,16 +1344,15 @@ if (flags & PBF_DELWRI) { pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC); - pb->pb_flags |= flags & - (PBF_DELWRI | PBF_ASYNC | PBF_SYNC); + pb->pb_flags |= flags & (PBF_DELWRI | PBF_ASYNC); pagebuf_delwri_queue(pb, 1); return status; } - pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | \ - PBF_DELWRI | PBF_READ_AHEAD | PBF_RUN_QUEUES); + pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_DELWRI | \ + PBF_READ_AHEAD | PBF_RUN_QUEUES); pb->pb_flags |= flags & (PBF_READ | PBF_WRITE | PBF_ASYNC | \ - PBF_SYNC | PBF_READ_AHEAD | PBF_RUN_QUEUES); + PBF_READ_AHEAD | PBF_RUN_QUEUES); BUG_ON(pb->pb_bn == PAGE_BUF_DADDR_NULL); @@ -1510,7 +1388,7 @@ return pb->pb_locked; if (pb->pb_flags & PBF_READ) return pb->pb_locked; - return (!(pb->pb_flags & _PBF_LOCKABLE)); + return (pb->pb_flags & _PBF_PAGECACHE); } STATIC void @@ -2000,7 +1878,6 @@ * Pagebuf delayed write buffer handling */ -STATIC int pbd_active = 1; STATIC LIST_HEAD(pbd_delwrite_queue); STATIC spinlock_t pbd_delwrite_lock = SPIN_LOCK_UNLOCKED; @@ -2020,12 +1897,11 @@ } list_add_tail(&pb->pb_list, &pbd_delwrite_queue); - pb->pb_flushtime = jiffies + pb_params.age_buffer.val; + pb->pb_flushtime = jiffies + xfs_age_buffer; spin_unlock(&pbd_delwrite_lock); - if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { + if (unlock) pagebuf_unlock(pb); - } } void @@ -2062,10 +1938,10 @@ daemonize(); /* Avoid signals */ - spin_lock_irq(¤t->sigmask_lock); + sigmask_lock(); sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + __recalc_sigpending(current); + sigmask_unlock(); /* Migrate to the right CPU */ migrate_to_cpu(cpu); @@ -2134,21 +2010,19 @@ /* Defines for pagebuf daemon */ -DECLARE_WAIT_QUEUE_HEAD(pbd_waitq); +STATIC DECLARE_COMPLETION(pagebuf_daemon_done); +STATIC struct task_struct *pagebuf_daemon_task; +STATIC int pagebuf_daemon_active; STATIC int force_flush; STATIC void -pagebuf_daemon_wakeup( - int flag) +pagebuf_daemon_wakeup(void) { - force_flush = flag; - if (waitqueue_active(&pbd_waitq)) { - wake_up_interruptible(&pbd_waitq); - } + force_flush = 1; + barrier(); + wake_up_process(pagebuf_daemon_task); } -typedef void (*timeout_fn)(unsigned long); - STATIC int pagebuf_daemon( void *data) @@ -2156,32 +2030,28 @@ int count; page_buf_t *pb; struct list_head *curr, *next, tmp; - struct timer_list pb_daemon_timer = - { {NULL, NULL}, 0, 0, (timeout_fn)pagebuf_daemon_wakeup }; /* Set up the thread */ daemonize(); + /* Mark it active */ + pagebuf_daemon_task = current; + pagebuf_daemon_active = 1; + barrier(); + /* Avoid signals */ - spin_lock_irq(¤t->sigmask_lock); + sigmask_lock(); sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + __recalc_sigpending(current); + sigmask_unlock(); - strcpy(current->comm, "pagebufd"); + strcpy(current->comm, "xfsbufd"); current->flags |= PF_MEMALLOC; INIT_LIST_HEAD(&tmp); do { - if (pbd_active == 1) { - mod_timer(&pb_daemon_timer, - jiffies + pb_params.flush_interval.val); - interruptible_sleep_on(&pbd_waitq); - } - - if (pbd_active == 0) { - del_timer_sync(&pb_daemon_timer); - } + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(xfs_flush_interval); spin_lock(&pbd_delwrite_lock); @@ -2191,10 +2061,8 @@ PB_TRACE(pb, "walkq1", (long)pagebuf_ispin(pb)); - if ((pb->pb_flags & PBF_DELWRI) && !pagebuf_ispin(pb) && - (((pb->pb_flags & _PBF_LOCKABLE) == 0) || - !pagebuf_cond_lock(pb))) { - + if ((pb->pb_flags & PBF_DELWRI) && + !pagebuf_ispin(pb) && !pagebuf_cond_lock(pb)) { if (!force_flush && time_before(jiffies, pb->pb_flushtime)) { pagebuf_unlock(pb); @@ -2203,10 +2071,7 @@ pb->pb_flags &= ~PBF_DELWRI; pb->pb_flags |= PBF_WRITE; - - list_del(&pb->pb_list); - list_add(&pb->pb_list, &tmp); - + list_move(&pb->pb_list, &tmp); count++; } } @@ -2225,12 +2090,9 @@ blk_run_queues(); force_flush = 0; - } while (pbd_active == 1); - - pbd_active = -1; - wake_up_interruptible(&pbd_waitq); + } while (pagebuf_daemon_active); - return 0; + complete_and_exit(&pagebuf_daemon_done, 0); } void @@ -2359,10 +2221,9 @@ { int cpu, pcpu; - pbd_active = 0; - - wake_up_interruptible(&pbd_waitq); - wait_event_interruptible(pbd_waitq, pbd_active); + pagebuf_daemon_active = 0; + barrier(); + wait_for_completion(&pagebuf_daemon_done); for (pcpu = 0; pcpu < min(smp_num_cpus, MAX_IO_DAEMONS); pcpu++) { cpu = CPU_TO_DAEMON(cpu_logical_map(pcpu)); @@ -2380,107 +2241,10 @@ } -/* - * Pagebuf sysctl interface - */ - -STATIC int -pb_stats_clear_handler( - ctl_table *ctl, - int write, - struct file *filp, - void *buffer, - size_t *lenp) -{ - int ret; - int *valp = ctl->data; - - ret = proc_dointvec_minmax(ctl, write, filp, buffer, lenp); - - if (!ret && write && *valp) { - printk("XFS Clearing pbstats\n"); - memset(&pbstats, 0, sizeof(pbstats)); - pb_params.stats_clear.val = 0; - } - - return ret; -} - -STATIC struct ctl_table_header *pagebuf_table_header; - -STATIC ctl_table pagebuf_table[] = { - {PB_FLUSH_INT, "flush_int", &pb_params.flush_interval.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &pb_params.flush_interval.min, &pb_params.flush_interval.max}, - - {PB_FLUSH_AGE, "flush_age", &pb_params.age_buffer.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &pb_params.age_buffer.min, &pb_params.age_buffer.max}, - - {PB_STATS_CLEAR, "stats_clear", &pb_params.stats_clear.val, - sizeof(int), 0644, NULL, &pb_stats_clear_handler, - &sysctl_intvec, NULL, - &pb_params.stats_clear.min, &pb_params.stats_clear.max}, - -#ifdef PAGEBUF_TRACE - {PB_DEBUG, "debug", &pb_params.debug.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &pb_params.debug.min, &pb_params.debug.max}, -#endif - {0} -}; - -STATIC ctl_table pagebuf_dir_table[] = { - {VM_PAGEBUF, "pagebuf", NULL, 0, 0555, pagebuf_table}, - {0} -}; - -STATIC ctl_table pagebuf_root_table[] = { - {CTL_VM, "vm", NULL, 0, 0555, pagebuf_dir_table}, - {0} -}; - -#ifdef CONFIG_PROC_FS -STATIC int -pagebuf_readstats( - char *buffer, - char **start, - off_t offset, - int count, - int *eof, - void *data) -{ - int i, len; - - len = 0; - len += sprintf(buffer + len, "pagebuf"); - for (i = 0; i < sizeof(pbstats) / sizeof(u_int32_t); i++) { - len += sprintf(buffer + len, " %u", - *(((u_int32_t*)&pbstats) + i)); - } - buffer[len++] = '\n'; - - if (offset >= len) { - *start = buffer; - *eof = 1; - return 0; - } - *start = buffer + offset; - if ((len -= offset) > count) - return count; - *eof = 1; - - return len; -} -#endif /* CONFIG_PROC_FS */ - STATIC int pagebuf_shaker(int number, unsigned int mask) { - pagebuf_daemon_wakeup(1); + pagebuf_daemon_wakeup(); return 0; } @@ -2494,14 +2258,6 @@ { int i; - pagebuf_table_header = register_sysctl_table(pagebuf_root_table, 1); - -#ifdef CONFIG_PROC_FS - if (proc_mkdir("fs/pagebuf", 0)) - create_proc_read_entry( - "fs/pagebuf/stat", 0, 0, pagebuf_readstats, NULL); -#endif - pagebuf_cache = kmem_cache_create("page_buf_t", sizeof(page_buf_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (pagebuf_cache == NULL) { @@ -2549,10 +2305,4 @@ kmem_cache_destroy(pagebuf_cache); kmem_shake_deregister(pagebuf_shaker); - - unregister_sysctl_table(pagebuf_table_header); -#ifdef CONFIG_PROC_FS - remove_proc_entry("fs/pagebuf/stat", NULL); - remove_proc_entry("fs/pagebuf", NULL); -#endif } diff -urN linux-2.4.25/fs/xfs/linux/xfs_buf.h linux-2.4.26/fs/xfs/linux/xfs_buf.h --- linux-2.4.25/fs/xfs/linux/xfs_buf.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_buf.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -47,6 +47,16 @@ #include #include +/* nptl patch changes where the sigmask_lock is defined */ +#ifdef CLONE_SIGNAL /* stock */ +#define sigmask_lock() spin_lock_irq(¤t->sigmask_lock); +#define sigmask_unlock() spin_unlock_irq(¤t->sigmask_lock); +#define __recalc_sigpending(x) recalc_sigpending(x) +#else /* nptl */ +#define sigmask_lock() spin_lock_irq(¤t->sighand->siglock); +#define sigmask_unlock() spin_unlock_irq(¤t->sighand->siglock); +#define __recalc_sigpending(x) recalc_sigpending() +#endif /* * Base types */ @@ -76,9 +86,6 @@ PBF_ASYNC = (1 << 4), /* initiator will not wait for completion */ PBF_NONE = (1 << 5), /* buffer not read at all */ PBF_DELWRI = (1 << 6), /* buffer has dirty pages */ - PBF_FREED = (1 << 7), /* buffer has been freed and is invalid */ - PBF_SYNC = (1 << 8), /* force updates to disk */ - PBF_MAPPABLE = (1 << 9),/* use directly-addressable pages */ PBF_STALE = (1 << 10), /* buffer has been staled, do not find it */ PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory */ PBF_FS_DATAIOD = (1 << 12), /* schedule IO completion on fs datad */ @@ -89,7 +96,7 @@ PBF_DONT_BLOCK = (1 << 15), /* do not block in current thread */ /* flags used only internally */ - _PBF_LOCKABLE = (1 << 16), /* page_buf_t may be locked */ + _PBF_PAGECACHE = (1 << 16), /* backed by pagecache */ _PBF_PRIVATE_BH = (1 << 17), /* do not use public buffer heads */ _PBF_ALL_PAGES_MAPPED = (1 << 18), /* all pages in range mapped */ _PBF_ADDR_ALLOCATED = (1 << 19), /* pb_addr space was allocated */ @@ -205,7 +212,7 @@ loff_t, /* starting offset of range */ size_t, /* length of range */ page_buf_flags_t); /* PBF_READ, PBF_WRITE, */ - /* PBF_FORCEIO, _PBF_LOCKABLE */ + /* PBF_FORCEIO, */ extern page_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with */ /* no memory or disk address */ @@ -270,7 +277,7 @@ page_buf_t *, /* buffer to start */ page_buf_flags_t); /* PBF_LOCK, PBF_ASYNC, */ /* PBF_READ, PBF_WRITE, */ - /* PBF_DELWRI, PBF_SYNC */ + /* PBF_DELWRI */ extern int pagebuf_iorequest( /* start real I/O */ page_buf_t *); /* buffer to convey to device */ @@ -403,7 +410,7 @@ #define XFS_BUF_BFLAGS(x) ((x)->pb_flags) #define XFS_BUF_ZEROFLAGS(x) \ - ((x)->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_SYNC|PBF_DELWRI)) + ((x)->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_DELWRI)) #define XFS_BUF_STALE(x) ((x)->pb_flags |= XFS_B_STALE) #define XFS_BUF_UNSTALE(x) ((x)->pb_flags &= ~XFS_B_STALE) @@ -555,17 +562,15 @@ #define xfs_buf_read(target, blkno, len, flags) \ pagebuf_get((target), (blkno), (len), \ - PBF_LOCK | PBF_READ | PBF_MAPPED | PBF_MAPPABLE) + PBF_LOCK | PBF_READ | PBF_MAPPED) #define xfs_buf_get(target, blkno, len, flags) \ pagebuf_get((target), (blkno), (len), \ - PBF_LOCK | PBF_MAPPED | PBF_MAPPABLE) + PBF_LOCK | PBF_MAPPED) #define xfs_buf_read_flags(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), \ - PBF_READ | PBF_MAPPABLE | flags) + pagebuf_get((target), (blkno), (len), PBF_READ | (flags)) #define xfs_buf_get_flags(target, blkno, len, flags) \ - pagebuf_get((target), (blkno), (len), \ - PBF_MAPPABLE | flags) + pagebuf_get((target), (blkno), (len), (flags)) static inline int xfs_bawrite(void *mp, page_buf_t *bp) { @@ -577,7 +582,7 @@ static inline void xfs_buf_relse(page_buf_t *bp) { - if ((bp->pb_flags & _PBF_LOCKABLE) && !bp->pb_relse) + if (!bp->pb_relse) pagebuf_unlock(bp); pagebuf_rele(bp); } @@ -608,7 +613,6 @@ int iowait = (pb->pb_flags & PBF_ASYNC) == 0; int error = 0; - pb->pb_flags |= PBF_SYNC; if (!iowait) pb->pb_flags |= PBF_RUN_QUEUES; diff -urN linux-2.4.25/fs/xfs/linux/xfs_file.c linux-2.4.26/fs/xfs/linux/xfs_file.c --- linux-2.4.25/fs/xfs/linux/xfs_file.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_file.c 2004-04-14 06:05:40.000000000 -0700 @@ -68,17 +68,18 @@ { struct inode *inode = file->f_dentry->d_inode; vnode_t *vp = LINVFS_GET_VP(inode); - int error; + size_t rval; if (unlikely(file->f_flags & O_DIRECT)) { ioflags |= IO_ISDIRECT; down_read(&inode->i_alloc_sem); - VOP_READ(vp, file, buf, size, offset, ioflags, NULL, error); + VOP_READ(vp, file, buf, size, offset, ioflags, NULL, rval); up_read(&inode->i_alloc_sem); } else { - VOP_READ(vp, file, buf, size, offset, ioflags, NULL, error); + VOP_READ(vp, file, buf, size, offset, ioflags, NULL, rval); } - return error; + + return rval; } STATIC ssize_t @@ -113,7 +114,7 @@ struct inode *inode = file->f_dentry->d_inode; vnode_t *vp = LINVFS_GET_VP(inode); loff_t pos; - int error; /* Use negative errors in this f'n */ + ssize_t rval; /* Use negative errors in this f'n */ if ((ssize_t) count < 0) return -EINVAL; @@ -125,10 +126,10 @@ if (pos < 0) return -EINVAL; - error = file->f_error; - if (error) { + rval = file->f_error; + if (rval) { file->f_error = 0; - return error; + return rval; } /* We allow multiple direct writers in, there is no @@ -137,16 +138,17 @@ if (unlikely(file->f_flags & O_DIRECT)) { ioflags |= IO_ISDIRECT; down_read(&inode->i_alloc_sem); - VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, error); + VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, rval); *ppos = pos; up_read(&inode->i_alloc_sem); } else { down(&inode->i_sem); - VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, error); + VOP_WRITE(vp, file, buf, count, &pos, ioflags, NULL, rval); *ppos = pos; up(&inode->i_sem); } - return error; + + return rval; } STATIC inline ssize_t diff -urN linux-2.4.25/fs/xfs/linux/xfs_globals.c linux-2.4.26/fs/xfs/linux/xfs_globals.c --- linux-2.4.25/fs/xfs/linux/xfs_globals.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_globals.c 2004-04-14 06:05:40.000000000 -0700 @@ -64,6 +64,8 @@ .inherit_sync = { 0, 1, 1 }, .inherit_nodump = { 0, 1, 1 }, .inherit_noatim = { 0, 1, 1 }, + .flush_interval = { HZ/2, HZ, 30*HZ }, + .age_buffer = { 1*HZ, 15*HZ, 300*HZ }, }; /* diff -urN linux-2.4.25/fs/xfs/linux/xfs_ioctl.c linux-2.4.26/fs/xfs/linux/xfs_ioctl.c --- linux-2.4.25/fs/xfs/linux/xfs_ioctl.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_ioctl.c 2004-04-14 06:05:40.000000000 -0700 @@ -310,7 +310,6 @@ struct dentry *dentry; vnode_t *vp; xfs_fsop_handlereq_t hreq; - struct list_head *lp; error = xfs_vget_fsop_handlereq(mp, parinode, CAP_SYS_ADMIN, arg, sizeof(xfs_fsop_handlereq_t), @@ -356,32 +355,13 @@ return new_fd; } - /* Now to find a dentry. If possible, get a well-connected one. */ - spin_lock(&dcache_lock); - for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { - dentry = list_entry(lp, struct dentry, d_alias); - if (! (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { - dget_locked(dentry); - dentry->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); - iput(inode); - goto found; - } - } - spin_unlock(&dcache_lock); - - /* ELSE didn't find dentry. Create anonymous dcache entry. */ - dentry = d_alloc_root(inode); + dentry = d_alloc_anon(inode); if (dentry == NULL) { iput(inode); put_unused_fd(new_fd); return -XFS_ERROR(ENOMEM); } - /* Keep nfsd happy. */ - dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; - - found: /* Ensure umount returns EBUSY on umounts while this file is open. */ mntget(parfilp->f_vfsmnt); @@ -721,9 +701,7 @@ error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, NULL); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_GETBMAP: @@ -755,9 +733,7 @@ case XFS_IOC_SWAPEXT: { error = xfs_swapext((struct xfs_swapext *)arg); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_FSCOUNTS: { @@ -785,6 +761,8 @@ /* input parameter is passed in resblks field of structure */ in = inout.resblks; error = xfs_reserve_blocks(mp, &in, &inout); + if (error) + return -error; if (copy_to_user((char *)arg, &inout, sizeof(inout))) return -XFS_ERROR(EFAULT); @@ -817,9 +795,7 @@ return -XFS_ERROR(EFAULT); error = xfs_growfs_data(mp, &in); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_FSGROWFSLOG: { @@ -832,9 +808,7 @@ return -XFS_ERROR(EFAULT); error = xfs_growfs_log(mp, &in); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_FSGROWFSRT: { @@ -847,9 +821,7 @@ return -XFS_ERROR(EFAULT); error = xfs_growfs_rt(mp, &in); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_FREEZE: @@ -864,19 +836,36 @@ xfs_fs_thaw(mp); return 0; + case XFS_IOC_GOINGDOWN: { + __uint32_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(in, (__uint32_t *)arg)) + return -XFS_ERROR(EFAULT); + + error = xfs_fs_goingdown(mp, in); + return -error; + } + case XFS_IOC_ERROR_INJECTION: { xfs_error_injection_t in; + if (!capable(CAP_SYS_ADMIN)) + return EPERM; + if (copy_from_user(&in, (char *)arg, sizeof(in))) return -XFS_ERROR(EFAULT); error = xfs_errortag_add(in.errtag, mp); - if (error) - return -error; - return 0; + return -error; } case XFS_IOC_ERROR_CLEARALL: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + error = xfs_errortag_clearall(mp); return -error; @@ -901,7 +890,7 @@ if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) return -XFS_ERROR(EPERM); - if (filp->f_flags & O_RDONLY) + if (!(filp->f_flags & FMODE_WRITE)) return -XFS_ERROR(EBADF); if (vp->v_type != VREG) diff -urN linux-2.4.25/fs/xfs/linux/xfs_iops.c linux-2.4.26/fs/xfs/linux/xfs_iops.c --- linux-2.4.25/fs/xfs/linux/xfs_iops.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_iops.c 2004-04-14 06:05:40.000000000 -0700 @@ -616,8 +616,7 @@ if (!size) xflags |= ATTR_KERNOVAL; - if (capable(CAP_SYS_ADMIN)) - xflags |= ATTR_KERNFULLS; + xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS; error = attr_generic_list(vp, data, size, xflags, &result); if (error < 0) diff -urN linux-2.4.25/fs/xfs/linux/xfs_linux.h linux-2.4.26/fs/xfs/linux/xfs_linux.h --- linux-2.4.25/fs/xfs/linux/xfs_linux.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_linux.h 2004-04-14 06:05:40.000000000 -0700 @@ -135,6 +135,8 @@ #define xfs_inherit_sync xfs_params.inherit_sync.val #define xfs_inherit_nodump xfs_params.inherit_nodump.val #define xfs_inherit_noatime xfs_params.inherit_noatim.val +#define xfs_flush_interval xfs_params.flush_interval.val +#define xfs_age_buffer xfs_params.age_buffer.val #define current_cpu() smp_processor_id() #define current_pid() (current->pid) diff -urN linux-2.4.25/fs/xfs/linux/xfs_lrw.c linux-2.4.26/fs/xfs/linux/xfs_lrw.c --- linux-2.4.25/fs/xfs/linux/xfs_lrw.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_lrw.c 2004-04-14 06:05:40.000000000 -0700 @@ -311,9 +311,10 @@ !(ioflags & IO_INVIS)) { int error; vrwlock_t locktype = VRWLOCK_READ; + int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), *offset, size, - FILP_DELAY_FLAG(file), &locktype); + dmflags, &locktype); if (error) { if (!(ioflags & IO_ISLOCKED)) xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -322,9 +323,13 @@ } if (unlikely(ioflags & IO_ISDIRECT)) { + xfs_rw_enter_trace(XFS_DIORD_ENTER, &ip->i_iocore, + buf, size, *offset, ioflags); ret = do_generic_direct_read(file, buf, size, offset); UPDATE_ATIME(file->f_dentry->d_inode); } else { + xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, + buf, size, *offset, ioflags); ret = generic_file_read(file, buf, size, offset); } @@ -593,7 +598,7 @@ if (size == 0) return 0; - io = &(xip->i_iocore); + io = &xip->i_iocore; mp = io->io_mount; xfs_check_frozen(mp, bdp, XFS_FREEZE_WRITE); @@ -645,11 +650,12 @@ if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) && !(ioflags & IO_INVIS) && !eventsent)) { loff_t savedsize = *offset; + int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); xfs_iunlock(xip, XFS_ILOCK_EXCL); error = XFS_SEND_DATA(xip->i_mount, DM_EVENT_WRITE, vp, *offset, size, - FILP_DELAY_FLAG(file), &locktype); + dmflags, &locktype); if (error) { if (iolock) xfs_iunlock(xip, iolock); return -error; diff -urN linux-2.4.25/fs/xfs/linux/xfs_lrw.h linux-2.4.26/fs/xfs/linux/xfs_lrw.h --- linux-2.4.25/fs/xfs/linux/xfs_lrw.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_lrw.h 2004-04-14 06:05:40.000000000 -0700 @@ -45,9 +45,7 @@ /* * Defines for the trace mechanisms in xfs_lrw.c. */ -#define XFS_RW_KTRACE_SIZE 64 -#define XFS_STRAT_KTRACE_SIZE 64 -#define XFS_STRAT_GTRACE_SIZE 512 +#define XFS_RW_KTRACE_SIZE 128 #define XFS_READ_ENTER 1 #define XFS_WRITE_ENTER 2 @@ -69,6 +67,12 @@ #define XFS_INVAL_CACHED 18 #define XFS_DIORD_ENTER 19 #define XFS_DIOWR_ENTER 20 +#define XFS_SENDFILE_ENTER 21 +#define XFS_WRITEPAGE_ENTER 22 +#define XFS_RELEASEPAGE_ENTER 23 +#define XFS_IOMAP_ALLOC_ENTER 24 +#define XFS_IOMAP_ALLOC_MAP 25 +#define XFS_IOMAP_UNWRITTEN 26 extern void xfs_rw_enter_trace(int, struct xfs_iocore *, const char *, size_t, loff_t, int); extern void xfs_inval_cached_trace(struct xfs_iocore *, diff -urN linux-2.4.25/fs/xfs/linux/xfs_stats.c linux-2.4.26/fs/xfs/linux/xfs_stats.c --- linux-2.4.25/fs/xfs/linux/xfs_stats.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_stats.c 2004-04-14 06:05:40.000000000 -0700 @@ -63,6 +63,7 @@ { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, { "icluster", XFSSTAT_END_INODE_CLUSTER }, { "vnodes", XFSSTAT_END_VNODE_OPS }, + { "buf", XFSSTAT_END_BUF }, }; for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) { diff -urN linux-2.4.25/fs/xfs/linux/xfs_stats.h linux-2.4.26/fs/xfs/linux/xfs_stats.h --- linux-2.4.25/fs/xfs/linux/xfs_stats.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_stats.h 2004-04-14 06:05:40.000000000 -0700 @@ -120,6 +120,16 @@ __uint32_t vn_reclaim; /* # times vn_reclaim called */ __uint32_t vn_remove; /* # times vn_remove called */ __uint32_t vn_free; /* # times vn_free called */ +#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9) + __uint32_t pb_get; + __uint32_t pb_create; + __uint32_t pb_get_locked; + __uint32_t pb_get_locked_waited; + __uint32_t pb_busy_locked; + __uint32_t pb_miss_locked; + __uint32_t pb_page_retries; + __uint32_t pb_page_found; + __uint32_t pb_get_read; /* Extra precision counters */ __uint64_t xs_xstrat_bytes; __uint64_t xs_write_bytes; diff -urN linux-2.4.25/fs/xfs/linux/xfs_super.c linux-2.4.26/fs/xfs/linux/xfs_super.c --- linux-2.4.25/fs/xfs/linux/xfs_super.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_super.c 2004-04-14 06:05:40.000000000 -0700 @@ -260,6 +260,30 @@ xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); } +struct dentry * +d_alloc_anon(struct inode *inode) +{ + struct dentry *dentry; + + spin_lock(&dcache_lock); + list_for_each_entry(dentry, &inode->i_dentry, d_alias) { + if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) + goto found; + } + spin_unlock(&dcache_lock); + + dentry = d_alloc_root(inode); + if (likely(dentry != NULL)) + dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + return dentry; + found: + dget_locked(dentry); + dentry->d_vfs_flags |= DCACHE_REFERENCED; + spin_unlock(&dcache_lock); + iput(inode); + return dentry; +} + /*ARGSUSED*/ int xfs_blkdev_get( @@ -484,10 +508,10 @@ daemonize(); reparent_to_init(); - spin_lock_irq(¤t->sigmask_lock); + sigmask_lock(); sigfillset(¤t->blocked); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + __recalc_sigpending(current); + sigmask_unlock(); sprintf(current->comm, "xfssyncd"); @@ -686,7 +710,6 @@ { vnode_t *vp; struct inode *inode = NULL; - struct list_head *lp; struct dentry *result; xfs_fid2_t xfid; vfs_t *vfsp = LINVFS_GET_VFS(sb); @@ -711,24 +734,12 @@ return ERR_PTR(-ESTALE) ; inode = LINVFS_GET_IP(vp); - spin_lock(&dcache_lock); - for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { - result = list_entry(lp,struct dentry, d_alias); - if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { - dget_locked(result); - result->d_vfs_flags |= DCACHE_REFERENCED; - spin_unlock(&dcache_lock); - iput(inode); - return result; - } - } - spin_unlock(&dcache_lock); - result = d_alloc_root(inode); - if (result == NULL) { + + result = d_alloc_anon(inode); + if (unlikely(result == NULL)) { iput(inode); return ERR_PTR(-ENOMEM); } - result->d_flags |= DCACHE_NFSD_DISCONNECTED; return result; } diff -urN linux-2.4.25/fs/xfs/linux/xfs_super.h linux-2.4.26/fs/xfs/linux/xfs_super.h --- linux-2.4.25/fs/xfs/linux/xfs_super.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_super.h 2004-04-14 06:05:40.000000000 -0700 @@ -44,6 +44,8 @@ #ifdef CONFIG_XFS_QUOTA # define vfs_insertquota(vfs) vfs_insertops(vfsp, &xfs_qmops) +extern void xfs_qm_init(void); +extern void xfs_qm_exit(void); # define vfs_initquota() xfs_qm_init() # define vfs_exitquota() xfs_qm_exit() #else @@ -133,4 +135,7 @@ extern void xfs_setsize_buftarg(struct pb_target *, unsigned int, unsigned int); extern unsigned int xfs_getsize_buftarg(struct pb_target *); +/* matching a 2.6 kernel export, thus no xfs_ prefix */ +extern struct dentry *d_alloc_anon(struct inode *inode); + #endif /* __XFS_SUPER_H__ */ diff -urN linux-2.4.25/fs/xfs/linux/xfs_sysctl.c linux-2.4.26/fs/xfs/linux/xfs_sysctl.c --- linux-2.4.25/fs/xfs/linux/xfs_sysctl.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_sysctl.c 2004-04-14 06:05:40.000000000 -0700 @@ -149,6 +149,16 @@ sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max}, + + {XFS_FLUSH_INTERVAL, "flush_interval", &xfs_params.flush_interval.val, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, + &xfs_params.flush_interval.min, &xfs_params.flush_interval.max}, + + {XFS_AGE_BUFFER, "age_buffer", &xfs_params.age_buffer.val, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, + &xfs_params.age_buffer.min, &xfs_params.age_buffer.max}, /* please keep this the last entry */ #ifdef CONFIG_PROC_FS diff -urN linux-2.4.25/fs/xfs/linux/xfs_sysctl.h linux-2.4.26/fs/xfs/linux/xfs_sysctl.h --- linux-2.4.25/fs/xfs/linux/xfs_sysctl.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_sysctl.h 2004-04-14 06:05:40.000000000 -0700 @@ -60,6 +60,10 @@ xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */ xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */ xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */ + xfs_sysctl_val_t flush_interval;/* interval between runs of the + * delwri flush daemon. */ + xfs_sysctl_val_t age_buffer; /* time for buffer to age before + * we flush it. */ } xfs_param_t; /* @@ -90,6 +94,8 @@ XFS_INHERIT_SYNC = 13, XFS_INHERIT_NODUMP = 14, XFS_INHERIT_NOATIME = 15, + XFS_FLUSH_INTERVAL = 16, + XFS_AGE_BUFFER = 17, }; extern xfs_param_t xfs_params; diff -urN linux-2.4.25/fs/xfs/linux/xfs_vfs.c linux-2.4.26/fs/xfs/linux/xfs_vfs.c --- linux-2.4.25/fs/xfs/linux/xfs_vfs.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/linux/xfs_vfs.c 2004-04-14 06:05:40.000000000 -0700 @@ -117,7 +117,6 @@ return ((*bhvtovfsops(next)->vfs_mntupdate)(next, fl, args)); } - int vfs_root( struct bhv_desc *bdp, diff -urN linux-2.4.25/fs/xfs/xfs_ag.h linux-2.4.26/fs/xfs/xfs_ag.h --- linux-2.4.25/fs/xfs/xfs_ag.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_ag.h 2004-04-14 06:05:40.000000000 -0700 @@ -230,39 +230,6 @@ xfs_perag_busy_t *pagb_list; /* unstable blocks */ } xfs_perag_t; -#define XFS_AG_MIN_BYTES (1LL << 24) /* 16 MB */ -#define XFS_AG_BEST_BYTES (1LL << 30) /* 1 GB */ -#define XFS_AG_MAX_BYTES (1LL << 32) /* 4 GB */ - -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MIN_BLOCKS) -xfs_extlen_t xfs_ag_min_blocks(int bl); -#define XFS_AG_MIN_BLOCKS(bl) xfs_ag_min_blocks(bl) -#else -#define XFS_AG_MIN_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MIN_BYTES >> bl)) -#endif -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_BEST_BLOCKS) -xfs_extlen_t xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks); -#define XFS_AG_BEST_BLOCKS(bl,blks) xfs_ag_best_blocks(bl,blks) -#else -/*--#define XFS_AG_BEST_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl))*/ -/* - * Best is XFS_AG_BEST_BLOCKS at and below 64 Gigabyte filesystems, and - * XFS_AG_MAX_BLOCKS above 64 Gigabytes. - */ -#define XFS_AG_BEST_BLOCKS(bl,blks) \ - ((xfs_extlen_t)((1LL << (36 - bl)) >= blks) ? \ - ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl)) : \ - XFS_AG_MAX_BLOCKS(bl)) -#endif -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAX_BLOCKS) -xfs_extlen_t xfs_ag_max_blocks(int bl); -#define XFS_AG_MAX_BLOCKS(bl) xfs_ag_max_blocks(bl) -#else -#define XFS_AG_MAX_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MAX_BYTES >> bl)) -#endif - -#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) - #if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAXLEVELS) int xfs_ag_maxlevels(struct xfs_mount *mp); #define XFS_AG_MAXLEVELS(mp) xfs_ag_maxlevels(mp) diff -urN linux-2.4.25/fs/xfs/xfs_alloc.c linux-2.4.26/fs/xfs/xfs_alloc.c --- linux-2.4.25/fs/xfs/xfs_alloc.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_alloc.c 2004-04-14 06:05:40.000000000 -0700 @@ -780,14 +780,8 @@ /* * Randomly don't execute the first algorithm. */ - static int seed; /* randomizing seed value */ int dofirst; /* set to do first algorithm */ - timespec_t now; /* current time */ - if (!seed) { - nanotime(&now); - seed = (int)now.tv_sec ^ (int)now.tv_nsec; - } dofirst = random() & 1; #endif /* diff -urN linux-2.4.25/fs/xfs/xfs_attr.h linux-2.4.26/fs/xfs/xfs_attr.h --- linux-2.4.25/fs/xfs/xfs_attr.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_attr.h 2004-04-14 06:05:40.000000000 -0700 @@ -91,10 +91,14 @@ #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ #define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */ + #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ #define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */ -#define ATTR_KERNFULLS 0x8000 /* [kernel] full attr list, ie. root+user */ + +#define ATTR_KERNORMALS 0x0800 /* [kernel] normal attr list: user+secure */ +#define ATTR_KERNROOTLS 0x8000 /* [kernel] include root in the attr list */ +#define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS) /* * The maximum size (into the kernel or returned from the kernel) of an diff -urN linux-2.4.25/fs/xfs/xfs_attr_leaf.c linux-2.4.26/fs/xfs/xfs_attr_leaf.c --- linux-2.4.25/fs/xfs/xfs_attr_leaf.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_attr_leaf.c 2004-04-14 06:05:40.000000000 -0700 @@ -460,9 +460,15 @@ i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { attrnames_t *namesp; + if (((context->flags & ATTR_SECURE) != 0) != + ((sfe->flags & XFS_ATTR_SECURE) != 0) && + !(context->flags & ATTR_KERNORMALS)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } if (((context->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0) && - !(context->flags & ATTR_KERNFULLS)) { + !(context->flags & ATTR_KERNROOTLS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } @@ -511,9 +517,15 @@ kmem_free(sbuf, sbsize); return XFS_ERROR(EFSCORRUPTED); } + if (((context->flags & ATTR_SECURE) != 0) != + ((sfe->flags & XFS_ATTR_SECURE) != 0) && + !(context->flags & ATTR_KERNORMALS)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } if (((context->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0) && - !(context->flags & ATTR_KERNFULLS)) { + !(context->flags & ATTR_KERNROOTLS)) { sfe = XFS_ATTR_SF_NEXTENTRY(sfe); continue; } @@ -563,8 +575,8 @@ for ( ; i < nsbuf; i++, sbp++) { attrnames_t *namesp; - namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure : - ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted : + namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure : + ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user); if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) { @@ -575,8 +587,7 @@ ASSERT(context->flags & ATTR_KERNAMELS); context->count += namesp->attr_namelen + sbp->namelen + 1; - } - else { + } else { if (xfs_attr_put_listent(context, namesp, sbp->name, sbp->namelen, INT_GET(sbp->valuelen, ARCH_CONVERT))) @@ -2309,9 +2320,13 @@ if (entry->flags & XFS_ATTR_INCOMPLETE) continue; /* skip incomplete entries */ + if (((context->flags & ATTR_SECURE) != 0) != + ((entry->flags & XFS_ATTR_SECURE) != 0) && + !(context->flags & ATTR_KERNORMALS)) + continue; /* skip non-matching entries */ if (((context->flags & ATTR_ROOT) != 0) != ((entry->flags & XFS_ATTR_ROOT) != 0) && - !(context->flags & ATTR_KERNFULLS)) + !(context->flags & ATTR_KERNROOTLS)) continue; /* skip non-matching entries */ namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure : diff -urN linux-2.4.25/fs/xfs/xfs_buf_item.c linux-2.4.26/fs/xfs/xfs_buf_item.c --- linux-2.4.25/fs/xfs/xfs_buf_item.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_buf_item.c 2004-04-14 06:05:40.000000000 -0700 @@ -429,7 +429,7 @@ */ if (bip->bli_flags & XFS_BLI_STALE_INODE) { xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip); - XFS_BUF_FSPRIVATE(bp, void *) = NULL; + XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); } else { AIL_LOCK(mp,s); diff -urN linux-2.4.25/fs/xfs/xfs_clnt.h linux-2.4.26/fs/xfs/xfs_clnt.h --- linux-2.4.25/fs/xfs/xfs_clnt.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_clnt.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -57,10 +57,10 @@ int flags; /* flags -> see XFSMNT_... macros below */ int logbufs; /* Number of log buffers, -1 to default */ int logbufsize; /* Size of log buffers, -1 to default */ - char fsname[MAXNAMELEN]; /* data device name */ - char rtname[MAXNAMELEN]; /* realtime device filename */ - char logname[MAXNAMELEN]; /* journal device filename */ - char mtpt[MAXNAMELEN]; /* filesystem mount point */ + char fsname[MAXNAMELEN+1]; /* data device name */ + char rtname[MAXNAMELEN+1]; /* realtime device filename */ + char logname[MAXNAMELEN+1]; /* journal device filename */ + char mtpt[MAXNAMELEN+1]; /* filesystem mount point */ int sunit; /* stripe unit (BBs) */ int swidth; /* stripe width (BBs), multiple of sunit */ uchar_t iosizelog; /* log2 of the preferred I/O size */ diff -urN linux-2.4.25/fs/xfs/xfs_dfrag.c linux-2.4.26/fs/xfs/xfs_dfrag.c --- linux-2.4.25/fs/xfs/xfs_dfrag.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_dfrag.c 2004-04-14 06:05:40.000000000 -0700 @@ -119,6 +119,11 @@ tip = XFS_BHVTOI(tbdp); } + if (ip->i_mount != tip->i_mount) { + error = XFS_ERROR(EINVAL); + goto error0; + } + if (ip->i_ino == tip->i_ino) { error = XFS_ERROR(EINVAL); goto error0; @@ -147,20 +152,17 @@ xfs_lock_inodes(ips, 2, 0, lock_flags); /* Check permissions */ - if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, NULL))) { - goto error0; - } - if ((error = _MAC_XFS_IACCESS(tip, MACWRITE, NULL))) { + error = xfs_iaccess(ip, S_IWUSR, NULL); + if (error) goto error0; - } - if ((current_fsuid(cred) != ip->i_d.di_uid) && - (error = xfs_iaccess(ip, S_IWUSR, NULL)) && - !capable_cred(NULL, CAP_FOWNER)) { + + error = xfs_iaccess(tip, S_IWUSR, NULL); + if (error) goto error0; - } - if ((current_fsuid(cred) != tip->i_d.di_uid) && - (error = xfs_iaccess(tip, S_IWUSR, NULL)) && - !capable_cred(NULL, CAP_FOWNER)) { + + /* Verify that both files have the same format */ + if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) { + error = XFS_ERROR(EINVAL); goto error0; } diff -urN linux-2.4.25/fs/xfs/xfs_dir2_node.c linux-2.4.26/fs/xfs/xfs_dir2_node.c --- linux-2.4.25/fs/xfs/xfs_dir2_node.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_dir2_node.c 2004-04-14 06:05:40.000000000 -0700 @@ -1573,15 +1573,16 @@ "%llu needed freesp block %lld for\n" " data block %lld, got %lld\n" " ifbno %llu lastfbno %d\n", - dp->i_ino, - XFS_DIR2_DB_TO_FDB(mp, dbno), - dbno, fbno, - ifbno, lastfbno); + (unsigned long long)dp->i_ino, + (long long)XFS_DIR2_DB_TO_FDB(mp, dbno), + (long long)dbno, (long long)fbno, + (unsigned long long)ifbno, lastfbno); if (fblk) { cmn_err(CE_ALERT, - " fblk 0x%llu blkno %llu " + " fblk 0x%p blkno %llu " "index %d magic 0x%x\n", - fblk, fblk->blkno, + fblk, + (unsigned long long)fblk->blkno, fblk->index, fblk->magic); } else { diff -urN linux-2.4.25/fs/xfs/xfs_dmapi.h linux-2.4.26/fs/xfs/xfs_dmapi.h --- linux-2.4.25/fs/xfs/xfs_dmapi.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_dmapi.h 2004-04-14 06:05:40.000000000 -0700 @@ -165,6 +165,27 @@ #define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ #define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ +#define DM_FLAGS_ISEM 0x004 /* thread holds i_sem */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,21) +/* i_alloc_sem was added in 2.4.22-pre1 */ +#define DM_FLAGS_IALLOCSEM_RD 0x010 /* thread holds i_alloc_sem rd */ +#define DM_FLAGS_IALLOCSEM_WR 0x020 /* thread holds i_alloc_sem wr */ +#endif +#endif + +/* + * Based on IO_ISDIRECT, decide which i_ flag is set. + */ +#ifdef DM_FLAGS_IALLOCSEM_RD +#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ + DM_FLAGS_IALLOCSEM_RD : DM_FLAGS_ISEM) +#define DM_SEM_FLAG_WR (DM_FLAGS_IALLOCSEM_WR | DM_FLAGS_ISEM) +#else +#define DM_SEM_FLAG_RD(ioflags) (((ioflags) & IO_ISDIRECT) ? \ + 0 : DM_FLAGS_ISEM) +#define DM_SEM_FLAG_WR (DM_FLAGS_ISEM) +#endif /* * Macros to turn caller specified delay/block flags into diff -urN linux-2.4.25/fs/xfs/xfs_dmops.c linux-2.4.26/fs/xfs/xfs_dmops.c --- linux-2.4.25/fs/xfs/xfs_dmops.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_dmops.c 2004-04-14 06:05:40.000000000 -0700 @@ -43,7 +43,7 @@ #include "xfs_dmapi.h" #include "xfs_mount.h" -xfs_dmops_t xfs_dmcore_xfs = { +xfs_dmops_t xfs_dmcore_stub = { .xfs_send_data = (xfs_send_data_t)fs_nosys, .xfs_send_mmap = (xfs_send_mmap_t)fs_noerr, .xfs_send_destroy = (xfs_send_destroy_t)fs_nosys, diff -urN linux-2.4.25/fs/xfs/xfs_error.c linux-2.4.26/fs/xfs/xfs_error.c --- linux-2.4.25/fs/xfs/xfs_error.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_error.c 2004-04-14 06:05:40.000000000 -0700 @@ -218,13 +218,17 @@ static void xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) { - char *newfmt; - int len = 16 + mp->m_fsname_len + strlen(fmt); - - newfmt = kmem_alloc(len, KM_SLEEP); - sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); - icmn_err(level, newfmt, ap); - kmem_free(newfmt, len); + if (mp != NULL) { + char *newfmt; + int len = 16 + mp->m_fsname_len + strlen(fmt); + + newfmt = kmem_alloc(len, KM_SLEEP); + sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); + icmn_err(level, newfmt, ap); + kmem_free(newfmt, len); + } else { + icmn_err(level, fmt, ap); + } } void @@ -267,16 +271,10 @@ inst_t *ra) { if (level <= xfs_error_level) { - if (mp != NULL) { - xfs_cmn_err(XFS_PTAG_ERROR_REPORT, - CE_ALERT, mp, + xfs_cmn_err(XFS_PTAG_ERROR_REPORT, + CE_ALERT, mp, "XFS internal error %s at line %d of file %s. Caller 0x%p\n", - tag, linenum, fname, ra); - } else { - cmn_err(CE_ALERT, - "XFS internal error %s at line %d of file %s. Caller 0x%p\n", - tag, linenum, fname, ra); - } + tag, linenum, fname, ra); xfs_stack_trace(); } diff -urN linux-2.4.25/fs/xfs/xfs_fs.h linux-2.4.26/fs/xfs/xfs_fs.h --- linux-2.4.25/fs/xfs/xfs_fs.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_fs.h 2004-04-14 06:05:40.000000000 -0700 @@ -437,6 +437,12 @@ #define FSHSIZE sizeof(fsid_t) +/* + * Flags for going down operation + */ +#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ +#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ +#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ /* * ioctl commands that replace IRIX fcntl()'s @@ -490,6 +496,7 @@ #define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) #define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) #define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) +#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) /* XFS_IOC_GETFSUUID ---------- deprecated 140 */ diff -urN linux-2.4.25/fs/xfs/xfs_fsops.c linux-2.4.26/fs/xfs/xfs_fsops.c --- linux-2.4.25/fs/xfs/xfs_fsops.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_fsops.c 2004-04-14 06:05:40.000000000 -0700 @@ -626,3 +626,28 @@ xfs_finish_freeze(mp); return 0; } + +int +xfs_fs_goingdown( + xfs_mount_t *mp, + __uint32_t inflags) +{ + switch (inflags) + { + case XFS_FSOP_GOING_FLAGS_DEFAULT: + xfs_fs_freeze(mp); + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); + xfs_fs_thaw(mp); + break; + case XFS_FSOP_GOING_FLAGS_LOGFLUSH: + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); + break; + case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: + xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR); + break; + default: + return XFS_ERROR(EINVAL); + } + + return 0; +} diff -urN linux-2.4.25/fs/xfs/xfs_fsops.h linux-2.4.26/fs/xfs/xfs_fsops.h --- linux-2.4.25/fs/xfs/xfs_fsops.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_fsops.h 2004-04-14 06:05:40.000000000 -0700 @@ -67,4 +67,9 @@ xfs_fs_thaw( xfs_mount_t *mp); +int +xfs_fs_goingdown( + xfs_mount_t *mp, + __uint32_t inflags); + #endif /* __XFS_FSOPS_H__ */ diff -urN linux-2.4.25/fs/xfs/xfs_inode.c linux-2.4.26/fs/xfs/xfs_inode.c --- linux-2.4.25/fs/xfs/xfs_inode.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_inode.c 2004-04-14 06:05:40.000000000 -0700 @@ -3707,13 +3707,13 @@ * Read/write DACs are always overridable. * Executable DACs are overridable if at least one exec bit is set. */ - if ((orgmode & (S_IRUSR|S_IWUSR)) || (inode->i_mode & S_IXUGO)) + if (!(orgmode & S_IXUSR) || + (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)) if (capable_cred(cr, CAP_DAC_OVERRIDE)) return 0; if ((orgmode == S_IRUSR) || - (((ip->i_d.di_mode & S_IFMT) == S_IFDIR) && - (!(orgmode & ~(S_IWUSR|S_IXUSR))))) { + (S_ISDIR(inode->i_mode) && (!(orgmode & S_IWUSR)))) { if (capable_cred(cr, CAP_DAC_READ_SEARCH)) return 0; #ifdef NOISE diff -urN linux-2.4.25/fs/xfs/xfs_iomap.c linux-2.4.26/fs/xfs/xfs_iomap.c --- linux-2.4.25/fs/xfs/xfs_iomap.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_iomap.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -69,6 +69,76 @@ #include "xfs_utils.h" #include "xfs_iomap.h" +#if defined(XFS_RW_TRACE) +void +xfs_iomap_enter_trace( + int tag, + xfs_iocore_t *io, + xfs_off_t offset, + ssize_t count) +{ + xfs_inode_t *ip = XFS_IO_INODE(io); + + if (!ip->i_rwtrace) + return; + + ktrace_enter(ip->i_rwtrace, + (void *)((unsigned long)tag), + (void *)ip, + (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), + (void *)((unsigned long)((offset >> 32) & 0xffffffff)), + (void *)((unsigned long)(offset & 0xffffffff)), + (void *)((unsigned long)count), + (void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(io->io_new_size & 0xffffffff)), + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL, + (void *)NULL); +} + +void +xfs_iomap_map_trace( + int tag, + xfs_iocore_t *io, + xfs_off_t offset, + ssize_t count, + xfs_iomap_t *iomapp, + xfs_bmbt_irec_t *imapp, + int flags) +{ + xfs_inode_t *ip = XFS_IO_INODE(io); + + if (!ip->i_rwtrace) + return; + + ktrace_enter(ip->i_rwtrace, + (void *)((unsigned long)tag), + (void *)ip, + (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)), + (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)), + (void *)((unsigned long)((offset >> 32) & 0xffffffff)), + (void *)((unsigned long)(offset & 0xffffffff)), + (void *)((unsigned long)count), + (void *)((unsigned long)flags), + (void *)((unsigned long)((iomapp->iomap_offset >> 32) & 0xffffffff)), + (void *)((unsigned long)(iomapp->iomap_offset & 0xffffffff)), + (void *)((unsigned long)(iomapp->iomap_delta)), + (void *)((unsigned long)(iomapp->iomap_bsize)), + (void *)((unsigned long)(iomapp->iomap_bn)), + (void *)(__psint_t)(imapp->br_startoff), + (void *)((unsigned long)(imapp->br_blockcount)), + (void *)(__psint_t)(imapp->br_startblock)); +} +#else +#define xfs_iomap_enter_trace(tag, io, offset, count) +#define xfs_iomap_map_trace(tag, io, offset, count, iomapp, imapp, flags) +#endif + #define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ << mp->m_writeio_log) #define XFS_STRAT_WRITE_IMAPS 2 @@ -149,17 +219,20 @@ (BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE | BMAPI_UNWRITTEN | BMAPI_DEVICE)) { case BMAPI_READ: + xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); lockmode = XFS_LCK_MAP_SHARED(mp, io); bmapi_flags = XFS_BMAPI_ENTIRE; if (flags & BMAPI_IGNSTATE) bmapi_flags |= XFS_BMAPI_IGSTATE; break; case BMAPI_WRITE: + xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR; bmapi_flags = 0; XFS_ILOCK(mp, io, lockmode); break; case BMAPI_ALLOCATE: + xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count); lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD; bmapi_flags = XFS_BMAPI_ENTIRE; /* Attempt non-blocking lock */ @@ -201,8 +274,11 @@ switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) { case BMAPI_WRITE: /* If we found an extent, return it */ - if (nimaps && (imap.br_startblock != HOLESTARTBLOCK)) + if (nimaps && (imap.br_startblock != HOLESTARTBLOCK)) { + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, + offset, count, iomapp, &imap, flags); break; + } if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) { error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset, @@ -211,6 +287,10 @@ error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, &imap, &nimaps); } + if (!error) { + xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io, + offset, count, iomapp, &imap, flags); + } iomap_flags = IOMAP_NEW; break; case BMAPI_ALLOCATE: @@ -218,8 +298,11 @@ XFS_IUNLOCK(mp, io, lockmode); lockmode = 0; - if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) + if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) { + xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io, + offset, count, iomapp, &imap, flags); break; + } error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps); break; @@ -309,7 +392,6 @@ * Make sure that the dquots are there. This doesn't hold * the ilock across a disk read. */ - error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED); if (error) return XFS_ERROR(error); @@ -540,8 +622,9 @@ * If bmapi returned us nothing, and if we didn't get back EDQUOT, * then we must have run out of space. */ - if (nimaps == 0) { + xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE, + io, offset, count); if (xfs_flush_space(ip, &fsynced, &ioflag)) return XFS_ERROR(ENOSPC); @@ -584,7 +667,6 @@ /* * Make sure that the dquots are there. */ - if ((error = XFS_QM_DQATTACH(mp, ip, 0))) return XFS_ERROR(error); @@ -612,7 +694,6 @@ XFS_WRITE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_WRITE_LOG_COUNT); - if (error == ENOSPC) { error = xfs_trans_reserve(tp, 0, XFS_WRITE_LOG_RES(mp), @@ -653,19 +734,16 @@ error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb, XFS_BMAPI_WRITE, &first_block, 1, imap, &nimaps, &free_list); - if (error) goto trans_cancel; error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); - if (error) goto trans_cancel; error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); - if (error) goto error0; @@ -725,6 +803,9 @@ xfs_fsblock_t firstfsb; xfs_bmap_free_t free_list; + xfs_iomap_enter_trace(XFS_IOMAP_UNWRITTEN, + &ip->i_iocore, offset, count); + offset_fsb = XFS_B_TO_FSBT(mp, offset); count_fsb = XFS_B_TO_FSB(mp, count); diff -urN linux-2.4.25/fs/xfs/xfs_log.c linux-2.4.26/fs/xfs/xfs_log.c --- linux-2.4.25/fs/xfs/xfs_log.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_log.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -759,8 +759,9 @@ /* Also an invalid lsn. 1 implies that we aren't passing in a valid * tail_lsn. */ - if (tail_lsn != 1) + if (tail_lsn != 1) { log->l_tail_lsn = tail_lsn; + } if ((tic = log->l_write_headq)) { #ifdef DEBUG @@ -866,10 +867,11 @@ tail_lsn = xfs_trans_tail_ail(mp); s = GRANT_LOCK(log); - if (tail_lsn != 0) + if (tail_lsn != 0) { log->l_tail_lsn = tail_lsn; - else + } else { tail_lsn = log->l_tail_lsn = log->l_last_sync_lsn; + } GRANT_UNLOCK(log, s); return tail_lsn; @@ -921,10 +923,8 @@ * In this case we just want to return the size of the * log as the amount of space left. */ -/* This assert does not take into account padding from striped log writes * ASSERT((tail_cycle == (cycle + 1)) || ((bytes + log->l_roundoff) >= tail_bytes)); -*/ free_bytes = log->l_logsize; } return free_bytes; @@ -940,7 +940,8 @@ void xlog_iodone(xfs_buf_t *bp) { - xlog_in_core_t *iclog; + xlog_in_core_t *iclog; + xlog_t *l; int aborted; iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); @@ -949,18 +950,19 @@ aborted = 0; /* + * Some versions of cpp barf on the recursive definition of + * ic_log -> hic_fields.ic_log and expand ic_log twice when + * it is passed through two macros. Workaround broken cpp. + */ + l = iclog->ic_log; + + /* * Race to shutdown the filesystem if we see an error. */ - if (XFS_BUF_GETERROR(bp)) { - /* Some versions of cpp barf on the recursive definition of - * ic_log -> hic_fields.ic_log and expand ic_log twice when - * it is passed through two macros. Workaround for broken cpp - */ - struct log *l; - xfs_ioerror_alert("xlog_iodone", - iclog->ic_log->l_mp, bp, XFS_BUF_ADDR(bp)); + if (XFS_TEST_ERROR((XFS_BUF_GETERROR(bp)), l->l_mp, + XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) { + xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp)); XFS_BUF_STALE(bp); - l = iclog->ic_log; xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR); /* * This flag will be propagated to the trans-committed @@ -1183,14 +1185,6 @@ log->l_grant_reserve_cycle = 1; log->l_grant_write_cycle = 1; - if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) { - if (mp->m_sb.sb_logsunit <= 1) { - log->l_stripemask = 1; - } else { - log->l_stripemask = 1 << - xfs_highbit32(mp->m_sb.sb_logsunit >> BBSHIFT); - } - } if (XFS_SB_VERSION_HASSECTOR(&mp->m_sb)) { log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT; ASSERT(log->l_sectbb_log <= mp->m_sectbb_log); @@ -1235,7 +1229,7 @@ kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); iclog = *iclogp; iclog->hic_data = (xlog_in_core_2_t *) - kmem_alloc(iclogsize, KM_SLEEP); + kmem_zalloc(iclogsize, KM_SLEEP); iclog->ic_prev = prev_iclog; prev_iclog = iclog; @@ -1401,45 +1395,35 @@ xfs_caddr_t dptr; /* pointer to byte sized element */ xfs_buf_t *bp; int i, ops; - uint roundup; uint count; /* byte count of bwrite */ + uint count_init; /* initial count before roundup */ int split = 0; /* split write into two regions */ int error; XFS_STATS_INC(xs_log_writes); ASSERT(iclog->ic_refcnt == 0); + /* Add for LR header */ + count_init = log->l_iclog_hsize + iclog->ic_offset; + /* Round out the log write size */ - if (iclog->ic_offset & BBMASK) { - /* count of 0 is already accounted for up in - * xlog_state_sync_all(). Once in this routine, - * operations on the iclog are single threaded. - * - * Difference between rounded up size and size - */ - count = iclog->ic_offset & BBMASK; - iclog->ic_roundoff += BBSIZE - count; - } - if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - unsigned sunit = BTOBB(log->l_mp->m_sb.sb_logsunit); - if (!sunit) - sunit = 1; - - count = BTOBB(log->l_iclog_hsize + iclog->ic_offset); - if (count & (sunit - 1)) { - roundup = sunit - (count & (sunit - 1)); - } else { - roundup = 0; - } - iclog->ic_offset += BBTOB(roundup); + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) && + log->l_mp->m_sb.sb_logsunit > 1) { + /* we have a v2 stripe unit to use */ + count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init)); + } else { + count = BBTOB(BTOBB(count_init)); } - + iclog->ic_roundoff = count - count_init; log->l_roundoff += iclog->ic_roundoff; xlog_pack_data(log, iclog); /* put cycle number in every block */ /* real byte length */ - INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); + INT_SET(iclog->ic_header.h_len, + ARCH_CONVERT, + iclog->ic_offset + iclog->ic_roundoff); + /* put ops count in correct order */ ops = iclog->ic_header.h_num_logops; INT_SET(iclog->ic_header.h_num_logops, ARCH_CONVERT, ops); @@ -1449,12 +1433,6 @@ XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); XFS_BUF_SET_ADDR(bp, BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT)); - /* Count is already rounded up to a BBSIZE above */ - count = iclog->ic_offset + iclog->ic_roundoff; - ASSERT((count & BBMASK) == 0); - - /* Add for LR header */ - count += log->l_iclog_hsize; XFS_STATS_ADD(xs_log_blocks, BTOBB(count)); /* Do we need to split this write into 2 parts? */ @@ -2783,8 +2761,6 @@ xlog_in_core_t *iclog, int eventual_size) { - uint roundup; - ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); if (!eventual_size) eventual_size = iclog->ic_offset; @@ -2797,14 +2773,10 @@ log->l_curr_block += BTOBB(eventual_size)+BTOBB(log->l_iclog_hsize); /* Round up to next log-sunit */ - if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { - if (log->l_curr_block & (log->l_stripemask - 1)) { - roundup = log->l_stripemask - - (log->l_curr_block & (log->l_stripemask - 1)); - } else { - roundup = 0; - } - log->l_curr_block += roundup; + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) && + log->l_mp->m_sb.sb_logsunit > 1) { + __uint32_t sunit_bb = BTOBB(log->l_mp->m_sb.sb_logsunit); + log->l_curr_block = roundup(log->l_curr_block, sunit_bb); } if (log->l_curr_block >= log->l_logBBsize) { @@ -3188,6 +3160,7 @@ uint xflags) { xlog_ticket_t *tic; + uint num_headers; SPLDECL(s); alloc: @@ -3211,21 +3184,30 @@ * in the log. A unit in this case is the amount of space for one * of these log operations. Normal reservations have a cnt of 1 * and their unit amount is the total amount of space required. - * The following line of code adds one log record header length - * for each part of an operation which may fall on a different - * log record. * - * One more XLOG_HEADER_SIZE is added to account for possible - * round off errors when syncing a LR to disk. The bytes are - * subtracted if the thread using this ticket is the first writer - * to a new LR. - * - * We add an extra log header for the possibility that the commit - * record is the first data written to a new log record. In this - * case it is separate from the rest of the transaction data and - * will be charged for the log record header. + * The following lines of code account for non-transaction data + * which occupy space in the on-disk log. */ - unit_bytes += log->l_iclog_hsize * (XLOG_BTOLRBB(unit_bytes) + 2); + + /* for start-rec */ + unit_bytes += sizeof(xlog_op_header_t); + + /* for padding */ + if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) && + log->l_mp->m_sb.sb_logsunit > 1) { + /* log su roundoff */ + unit_bytes += log->l_mp->m_sb.sb_logsunit; + } else { + /* BB roundoff */ + unit_bytes += BBSIZE; + } + + /* for commit-rec */ + unit_bytes += sizeof(xlog_op_header_t); + + /* for LR headers */ + num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log); + unit_bytes += log->l_iclog_hsize * num_headers; tic->t_unit_res = unit_bytes; tic->t_curr_res = unit_bytes; diff -urN linux-2.4.25/fs/xfs/xfs_log_priv.h linux-2.4.26/fs/xfs/xfs_log_priv.h --- linux-2.4.25/fs/xfs/xfs_log_priv.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_log_priv.h 2004-04-14 06:05:40.000000000 -0700 @@ -57,12 +57,9 @@ #define XLOG_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ #define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */ #define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */ -#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_BTOLRBB) -int xlog_btolrbb(int b); -#define XLOG_BTOLRBB(b) xlog_btolrbb(b) -#else -#define XLOG_BTOLRBB(b) (((b)+XLOG_RECORD_BSIZE-1) >> XLOG_RECORD_BSHIFT) -#endif +#define XLOG_BTOLSUNIT(log, b) (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \ + (log)->l_mp->m_sb.sb_logsunit) +#define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit) #define XLOG_HEADER_SIZE 512 @@ -531,7 +528,6 @@ uint l_flags; uint l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */ struct xfs_buf_cancel **l_buf_cancel_table; - int l_stripemask; /* log stripe mask */ int l_iclog_hsize; /* size of iclog header */ int l_iclog_heads; /* # of iclog header sectors */ uint l_sectbb_log; /* log2 of sector size in BBs */ @@ -558,6 +554,7 @@ extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *); +/* iclog tracing */ #define XLOG_TRACE_GRAB_FLUSH 1 #define XLOG_TRACE_REL_FLUSH 2 #define XLOG_TRACE_SLEEP_FLUSH 3 diff -urN linux-2.4.25/fs/xfs/xfs_log_recover.c linux-2.4.26/fs/xfs/xfs_log_recover.c --- linux-2.4.25/fs/xfs/xfs_log_recover.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_log_recover.c 2004-04-14 06:05:40.000000000 -0700 @@ -3416,6 +3416,7 @@ { uint *up = (uint *)dp; uint chksum = 0; + int i; /* divide length by 4 to get # words */ for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { @@ -3476,7 +3477,7 @@ xlog_rec_header_t *rhead, xfs_daddr_t blkno) { - int bblks; + int hlen; if (unlikely( (INT_GET(rhead->h_magicno, ARCH_CONVERT) != @@ -3495,8 +3496,8 @@ } /* LR body must have data or it wouldn't have been written */ - bblks = INT_GET(rhead->h_len, ARCH_CONVERT); - if (unlikely( bblks <= 0 || bblks > INT_MAX )) { + hlen = INT_GET(rhead->h_len, ARCH_CONVERT); + if (unlikely( hlen <= 0 || hlen > INT_MAX )) { XFS_ERROR_REPORT("xlog_valid_rec_header(2)", XFS_ERRLEVEL_LOW, log->l_mp); return XFS_ERROR(EFSCORRUPTED); @@ -3658,7 +3659,7 @@ error = xlog_bread(log, 0, wrapped_hblks, hbp); if (error) goto bread_err2; - XFS_BUF_SET_PTR(hbp, bufaddr, hblks); + XFS_BUF_SET_PTR(hbp, bufaddr, BBTOB(hblks)); if (!offset) offset = xlog_align(log, 0, wrapped_hblks, hbp); @@ -3716,8 +3717,7 @@ if ((error = xlog_bread(log, wrapped_hblks, bblks - split_bblks, dbp))) goto bread_err2; - XFS_BUF_SET_PTR(dbp, bufaddr, - XLOG_BIG_RECORD_BSIZE); + XFS_BUF_SET_PTR(dbp, bufaddr, h_size); if (!offset) offset = xlog_align(log, wrapped_hblks, bblks - split_bblks, dbp); @@ -4042,7 +4042,7 @@ XFS_FSS_TO_BB(mp, 1), 0); if (XFS_BUF_ISERROR(agibp)) { xfs_ioerror_alert("xlog_recover_check_summary(agi)", - log->l_mp, agibp, agidaddr); + mp, agibp, agidaddr); } agip = XFS_BUF_TO_AGI(agibp); ASSERT(XFS_AGI_MAGIC == @@ -4058,7 +4058,8 @@ sbbp = xfs_getsb(mp, 0); #ifdef XFS_LOUD_RECOVERY - sbp = XFS_BUF_TO_SBP(sbbp); + sbp = &mp->m_sb; + xfs_xlatesb(XFS_BUF_TO_SBP(sbbp), sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); cmn_err(CE_NOTE, "xlog_recover_check_summary: sb_icount %Lu itotal %Lu", sbp->sb_icount, itotal); diff -urN linux-2.4.25/fs/xfs/xfs_macros.c linux-2.4.26/fs/xfs/xfs_macros.c --- linux-2.4.25/fs/xfs/xfs_macros.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_macros.c 2004-04-14 06:05:40.000000000 -0700 @@ -115,22 +115,6 @@ } #endif -#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_BEST_BLOCKS) -xfs_extlen_t -xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks) -{ - return XFS_AG_BEST_BLOCKS(bl, blks); -} -#endif - -#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAX_BLOCKS) -xfs_extlen_t -xfs_ag_max_blocks(int bl) -{ - return XFS_AG_MAX_BLOCKS(bl); -} -#endif - #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAXLEVELS) int xfs_ag_maxlevels(xfs_mount_t *mp) @@ -139,14 +123,6 @@ } #endif -#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MIN_BLOCKS) -xfs_extlen_t -xfs_ag_min_blocks(int bl) -{ - return XFS_AG_MIN_BLOCKS(bl); -} -#endif - #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGB_TO_DADDR) xfs_daddr_t xfs_agb_to_daddr(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) @@ -2243,14 +2219,6 @@ } #endif -#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_BTOLRBB) -int -xlog_btolrbb(int b) -{ - return XLOG_BTOLRBB(b); -} -#endif - #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_ADD_SPACE) void xlog_grant_add_space(xlog_t *log, int bytes, int type) diff -urN linux-2.4.25/fs/xfs/xfs_mount.c linux-2.4.26/fs/xfs/xfs_mount.c --- linux-2.4.25/fs/xfs/xfs_mount.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_mount.c 2004-04-14 06:05:40.000000000 -0700 @@ -675,6 +675,7 @@ error = XFS_ERROR(EINVAL); goto error1; } + mp->m_dalign = mp->m_swidth = 0; } else { /* * Convert the stripe unit and width to FSBs. diff -urN linux-2.4.25/fs/xfs/xfs_mount.h linux-2.4.26/fs/xfs/xfs_mount.h --- linux-2.4.25/fs/xfs/xfs_mount.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_mount.h 2004-04-14 06:05:40.000000000 -0700 @@ -571,8 +571,8 @@ extern struct vfsops xfs_vfsops; extern struct vnodeops xfs_vnodeops; -extern struct xfs_dmops xfs_dmcore_xfs; -extern struct xfs_qmops xfs_qmcore_xfs; +extern struct xfs_dmops xfs_dmcore_stub; +extern struct xfs_qmops xfs_qmcore_stub; extern struct xfs_ioops xfs_iocore_xfs; extern int xfs_init(void); diff -urN linux-2.4.25/fs/xfs/xfs_qmops.c linux-2.4.26/fs/xfs/xfs_qmops.c --- linux-2.4.25/fs/xfs/xfs_qmops.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_qmops.c 2004-04-14 06:05:40.000000000 -0700 @@ -54,7 +54,7 @@ return NULL; } -xfs_qmops_t xfs_qmcore_xfs = { +xfs_qmops_t xfs_qmcore_stub = { .xfs_qminit = (xfs_qminit_t) fs_noerr, .xfs_qmdone = (xfs_qmdone_t) fs_noerr, .xfs_qmmount = (xfs_qmmount_t) fs_noerr, diff -urN linux-2.4.25/fs/xfs/xfs_quota.h linux-2.4.26/fs/xfs/xfs_quota.h --- linux-2.4.25/fs/xfs/xfs_quota.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_quota.h 2004-04-14 06:05:40.000000000 -0700 @@ -347,9 +347,6 @@ extern struct bhv_vfsops xfs_qmops; -extern void xfs_qm_init(void); -extern void xfs_qm_exit(void); - #endif /* __KERNEL__ */ #endif /* __XFS_QUOTA_H__ */ diff -urN linux-2.4.25/fs/xfs/xfs_trans.h linux-2.4.26/fs/xfs/xfs_trans.h --- linux-2.4.25/fs/xfs/xfs_trans.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_trans.h 2004-04-14 06:05:40.000000000 -0700 @@ -535,6 +535,8 @@ * the super block to reflect the freed blocks: sector size * worst case split in allocation btrees per extent assuming 4 extents: * 4 exts * 2 trees * (2 * max depth - 1) * block size + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size */ #define XFS_CALC_ITRUNCATE_LOG_RES(mp) \ (MAX( \ @@ -545,7 +547,11 @@ (4 * (mp)->m_sb.sb_sectsize) + \ (mp)->m_sb.sb_sectsize + \ XFS_ALLOCFREE_LOG_RES(mp, 4) + \ - (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))) + \ + (128 * 5) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) #define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) @@ -713,6 +719,7 @@ XFS_FSB_TO_B((mp), 1) + \ MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \ (128 * 5) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) diff -urN linux-2.4.25/fs/xfs/xfs_vfsops.c linux-2.4.26/fs/xfs/xfs_vfsops.c --- linux-2.4.25/fs/xfs/xfs_vfsops.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_vfsops.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,7 +1,7 @@ /* * XFS filesystem operations. * - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -229,7 +229,10 @@ mp->m_swidth = ap->swidth; } - if (ap->logbufs != 0 && ap->logbufs != -1 && + if (ap->logbufs != -1 && +#if defined(DEBUG) || defined(XLOG_NOLOG) + ap->logbufs != 0 && +#endif (ap->logbufs < XLOG_MIN_ICLOGS || ap->logbufs > XLOG_MAX_ICLOGS)) { cmn_err(CE_WARN, @@ -451,9 +454,9 @@ * Setup xfs_mount function vectors from available behaviors */ p = vfs_bhv_lookup(vfsp, VFS_POSITION_DM); - mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_xfs; + mp->m_dm_ops = p ? *(xfs_dmops_t *) vfs_bhv_custom(p) : xfs_dmcore_stub; p = vfs_bhv_lookup(vfsp, VFS_POSITION_QM); - mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_xfs; + mp->m_qm_ops = p ? *(xfs_qmops_t *) vfs_bhv_custom(p) : xfs_qmcore_stub; p = vfs_bhv_lookup(vfsp, VFS_POSITION_IO); mp->m_io_ops = p ? *(xfs_ioops_t *) vfs_bhv_custom(p) : xfs_iocore_xfs; @@ -1482,8 +1485,10 @@ */ if (XFS_BUF_ISPINNED(bp)) xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); - if (!(flags & SYNC_WAIT)) - XFS_BUF_BFLAGS(bp) |= XFS_B_ASYNC; + if (flags & SYNC_WAIT) + XFS_BUF_UNASYNC(bp); + else + XFS_BUF_ASYNC(bp); error = xfs_bwrite(mp, bp); } if (error) { diff -urN linux-2.4.25/fs/xfs/xfs_vnodeops.c linux-2.4.26/fs/xfs/xfs_vnodeops.c --- linux-2.4.25/fs/xfs/xfs_vnodeops.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/fs/xfs/xfs_vnodeops.c 2004-04-14 06:05:40.000000000 -0700 @@ -413,8 +413,9 @@ } else { if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) && !(flags & ATTR_DMI)) { + int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, vp, - vap->va_size, 0, AT_DELAY_FLAG(flags), NULL); + vap->va_size, 0, dmflags, NULL); if (code) { lock_flags = 0; goto error_return; @@ -1105,14 +1106,11 @@ xfs_off_t stop) { xfs_inode_t *ip; - int error; - int error2; - int syncall; - vnode_t *vp; xfs_trans_t *tp; + int error; - vp = BHV_TO_VNODE(bdp); - vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); + vn_trace_entry(BHV_TO_VNODE(bdp), + __FUNCTION__, (inst_t *)__return_address); ip = XFS_BHVTOI(bdp); @@ -1121,44 +1119,6 @@ if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return XFS_ERROR(EIO); - xfs_ilock(ip, XFS_IOLOCK_EXCL); - - syncall = error = error2 = 0; - - if (stop == -1) { - ASSERT(start >= 0); - if (start == 0) - syncall = 1; - stop = xfs_file_last_byte(ip); - } - - /* - * If we're invalidating, always flush since we want to - * tear things down. Otherwise, don't flush anything if - * we're not dirty. - */ - if (flag & FSYNC_INVAL) { - if (ip->i_df.if_flags & XFS_IFEXTENTS && - ip->i_df.if_bytes > 0) { - VOP_FLUSHINVAL_PAGES(vp, start, -1, FI_REMAPF_LOCKED); - } - ASSERT(syncall == 0 || (VN_CACHED(vp) == 0)); - } else { - /* - * In the non-invalidating case, calls to fsync() do not - * flush all the dirty mmap'd pages. That requires a - * call to msync(). - */ - VOP_FLUSH_PAGES(vp, start, -1, - (flag & FSYNC_WAIT) ? 0 : XFS_B_ASYNC, - FI_NONE, error2); - } - - if (error2) { - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - return XFS_ERROR(error2); - } - /* * We always need to make sure that the required inode state * is safe on disk. The vnode might be clean but because @@ -1198,7 +1158,7 @@ * be pinned. If it is, force the log. */ - xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED); + xfs_iunlock(ip, XFS_ILOCK_SHARED); if (xfs_ipincount(ip)) { xfs_log_force(ip->i_mount, (xfs_lsn_t)0, @@ -1221,7 +1181,6 @@ XFS_FSYNC_TS_LOG_RES(ip->i_mount), 0, 0, 0))) { xfs_trans_cancel(tp, 0); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); @@ -1236,68 +1195,18 @@ * inode in another recent transaction. So we * play it safe and fire off the transaction anyway. */ - xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); xfs_trans_ihold(tp, ip); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (flag & FSYNC_WAIT) xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); - xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); } return error; } - -#if 0 -/* - * This is a utility routine for xfs_inactive. It is called when a - * transaction attempting to free up the disk space for a file encounters - * an error. It cancels the old transaction and starts up a new one - * to be used to free up the inode. It also sets the inode size and extent - * counts to 0 and frees up any memory being used to store inline data, - * extents, or btree roots. - */ -STATIC void -xfs_itruncate_cleanup( - xfs_trans_t **tpp, - xfs_inode_t *ip, - int commit_flags, - int fork) -{ - xfs_mount_t *mp; - /* REFERENCED */ - int error; - - mp = ip->i_mount; - if (*tpp) { - xfs_trans_cancel(*tpp, commit_flags | XFS_TRANS_ABORT); - } - xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - *tpp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); - error = xfs_trans_reserve(*tpp, 0, XFS_IFREE_LOG_RES(mp), 0, 0, - XFS_DEFAULT_LOG_COUNT); - if (error) { - return; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); - xfs_trans_ijoin(*tpp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - xfs_trans_ihold(*tpp, ip); - - xfs_idestroy_fork(ip, fork); - - if (fork == XFS_DATA_FORK) { - ip->i_d.di_nblocks = 0; - ip->i_d.di_nextents = 0; - ip->i_d.di_size = 0; - } else { - ip->i_d.di_anextents = 0; - } - xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); -} -#endif - /* * This is called by xfs_inactive to free any blocks beyond eof, * when the link count isn't zero. diff -urN linux-2.4.25/include/acpi/acconfig.h linux-2.4.26/include/acpi/acconfig.h --- linux-2.4.25/include/acpi/acconfig.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/acconfig.h 2004-04-14 06:05:40.000000000 -0700 @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040116 +#define ACPI_CA_VERSION 0x20040326 /* Maximum objects in the various object caches */ @@ -185,6 +185,10 @@ #define ACPI_SMBUS_BUFFER_SIZE 34 +/* Number of strings associated with the _OSI reserved method */ + +#define ACPI_NUM_OSI_STRINGS 4 + /****************************************************************************** * diff -urN linux-2.4.25/include/acpi/acglobal.h linux-2.4.26/include/acpi/acglobal.h --- linux-2.4.25/include/acpi/acglobal.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/acglobal.h 2004-04-14 06:05:40.000000000 -0700 @@ -57,6 +57,12 @@ #define ACPI_EXTERN extern #endif +/* + * Keep local copies of these FADT-based registers. NOTE: These globals + * are first in this file for alignment reasons on 64-bit systems. + */ +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; /***************************************************************************** * @@ -73,6 +79,15 @@ extern u32 acpi_gbl_nesting_level; +/***************************************************************************** + * + * Runtime configuration + * + ****************************************************************************/ + +ACPI_EXTERN u8 acpi_gbl_create_osi_method; +ACPI_EXTERN u8 acpi_gbl_all_methods_serialized; +ACPI_EXTERN u8 acpi_gbl_leave_wake_gpes_disabled; /***************************************************************************** * @@ -97,6 +112,11 @@ ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; +/* + * Since there may be multiple SSDTs and PSDTS, a single pointer is not + * sufficient; Therefore, there isn't one! + */ + /* * Handle both ACPI 1.0 and ACPI 2.0 Integer widths @@ -107,17 +127,6 @@ ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; -/* Keep local copies of these FADT-based registers */ - -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; - -/* - * Since there may be multiple SSDTs and PSDTS, a single pointer is not - * sufficient; Therefore, there isn't one! - */ - - /* * ACPI Table info arrays */ @@ -165,9 +174,11 @@ extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; -extern const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; +extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS]; /***************************************************************************** @@ -178,7 +189,7 @@ #define NUM_NS_TYPES ACPI_TYPE_INVALID+1 -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) #define NUM_PREDEFINED_NAMES 10 #else #define NUM_PREDEFINED_NAMES 9 @@ -186,6 +197,7 @@ ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct; ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device; extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; extern const struct acpi_predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; diff -urN linux-2.4.25/include/acpi/achware.h linux-2.4.26/include/acpi/achware.h --- linux-2.4.25/include/acpi/achware.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/achware.h 2004-04-14 06:05:40.000000000 -0700 @@ -149,11 +149,11 @@ acpi_event_status *event_status); acpi_status -acpi_hw_disable_non_wakeup_gpes ( +acpi_hw_prepare_gpes_for_sleep ( void); acpi_status -acpi_hw_enable_non_wakeup_gpes ( +acpi_hw_restore_gpes_on_wake ( void); diff -urN linux-2.4.25/include/acpi/aclocal.h linux-2.4.26/include/acpi/aclocal.h --- linux-2.4.25/include/acpi/aclocal.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/aclocal.h 2004-04-14 06:05:40.000000000 -0700 @@ -360,6 +360,13 @@ }; +struct acpi_gpe_walk_info +{ + struct acpi_namespace_node *gpe_device; + struct acpi_gpe_block_info *gpe_block; +}; + + typedef acpi_status (*ACPI_GPE_CALLBACK) ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); diff -urN linux-2.4.25/include/acpi/acmacros.h linux-2.4.26/include/acpi/acmacros.h --- linux-2.4.25/include/acpi/acmacros.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/acmacros.h 2004-04-14 06:05:40.000000000 -0700 @@ -681,7 +681,4 @@ #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ - -#define ACPI_GET_STACK_POINTER _asm {mov eax, ebx} - #endif /* ACMACROS_H */ diff -urN linux-2.4.25/include/acpi/acobject.h linux-2.4.26/include/acpi/acobject.h --- linux-2.4.25/include/acpi/acobject.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/acobject.h 2004-04-14 06:05:40.000000000 -0700 @@ -180,7 +180,11 @@ }; -#define INFINITE_CONCURRENCY 0xFF +#define ACPI_INFINITE_CONCURRENCY 0xFF + +typedef +acpi_status (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *walk_state); struct acpi_object_method { @@ -190,6 +194,7 @@ u32 aml_length; void *semaphore; u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; u8 concurrency; u8 thread_count; acpi_owner_id owning_id; diff -urN linux-2.4.25/include/acpi/acpi_bus.h linux-2.4.26/include/acpi/acpi_bus.h --- linux-2.4.25/include/acpi/acpi_bus.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/acpi/acpi_bus.h 2004-04-14 06:05:40.000000000 -0700 @@ -35,8 +35,6 @@ #include -extern int acpi_disabled; - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { diff -urN linux-2.4.25/include/acpi/actypes.h linux-2.4.26/include/acpi/actypes.h --- linux-2.4.25/include/acpi/actypes.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/actypes.h 2004-04-14 06:05:40.000000000 -0700 @@ -349,7 +349,6 @@ /* * Power state values */ - #define ACPI_STATE_UNKNOWN (u8) 0xFF #define ACPI_STATE_S0 (u8) 0 @@ -393,7 +392,6 @@ #define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6 #define ACPI_NOTIFY_POWER_FAULT (u8) 7 - /* * Table types. These values are passed to the table related APIs */ @@ -409,14 +407,13 @@ #define ACPI_TABLE_MAX 6 #define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1) - /* * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition * of the ACPI object_type() operator (See the ACPI Spec). Therefore, * only add to the first group if the spec changes. * - * Types must be kept in sync with the global acpi_ns_properties + * NOTE: Types must be kept in sync with the global acpi_ns_properties * and acpi_ns_type_names arrays. */ typedef u32 acpi_object_type; @@ -453,26 +450,27 @@ #define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 #define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, ref_of, Index */ #define ACPI_TYPE_LOCAL_ALIAS 0x15 -#define ACPI_TYPE_LOCAL_NOTIFY 0x16 -#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x17 -#define ACPI_TYPE_LOCAL_RESOURCE 0x18 -#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x19 -#define ACPI_TYPE_LOCAL_SCOPE 0x1A /* 1 Name, multiple object_list Nodes */ +#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 +#define ACPI_TYPE_LOCAL_NOTIFY 0x17 +#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 +#define ACPI_TYPE_LOCAL_RESOURCE 0x19 +#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A +#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */ -#define ACPI_TYPE_NS_NODE_MAX 0x1A /* Last typecode used within a NS Node */ +#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ /* * These are special object types that never appear in * a Namespace node, only in an union acpi_operand_object */ -#define ACPI_TYPE_LOCAL_EXTRA 0x1B -#define ACPI_TYPE_LOCAL_DATA 0x1C +#define ACPI_TYPE_LOCAL_EXTRA 0x1C +#define ACPI_TYPE_LOCAL_DATA 0x1D -#define ACPI_TYPE_LOCAL_MAX 0x1C +#define ACPI_TYPE_LOCAL_MAX 0x1D /* All types above here are invalid */ -#define ACPI_TYPE_INVALID 0x1D +#define ACPI_TYPE_INVALID 0x1E #define ACPI_TYPE_NOT_FOUND 0xFF @@ -514,9 +512,8 @@ #define ACPI_WRITE 1 #define ACPI_IO_MASK 1 - /* - * Acpi Event Types: Fixed & General Purpose + * Event Types: Fixed & General Purpose */ typedef u32 acpi_event_type; @@ -531,25 +528,8 @@ #define ACPI_EVENT_MAX 4 #define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 -#define ACPI_GPE_INVALID 0xFF -#define ACPI_GPE_MAX 0xFF -#define ACPI_NUM_GPE 256 - -#define ACPI_EVENT_LEVEL_TRIGGERED 1 -#define ACPI_EVENT_EDGE_TRIGGERED 2 - -/* - * Flags for GPE and Lock interfaces - */ -#define ACPI_EVENT_WAKE_ENABLE 0x2 -#define ACPI_EVENT_WAKE_DISABLE 0x2 - -#define ACPI_NOT_ISR 0x1 -#define ACPI_ISR 0x0 - - /* - * acpi_event Status: + * Event Status - Per event * ------------- * The encoding of acpi_event_status is illustrated below. * Note that a set bit (1) indicates the property is TRUE @@ -570,6 +550,45 @@ #define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 +/* + * General Purpose Events (GPE) + */ +#define ACPI_GPE_INVALID 0xFF +#define ACPI_GPE_MAX 0xFF +#define ACPI_NUM_GPE 256 + +/* + * GPE info flags - Per GPE + * +---------+-+-+-+ + * |Bits 8:3 |2|1|0| + * +---------+-+-+-+ + * | | | | + * | | | +- Edge or Level Triggered + * | | +--- Type: Wake or Runtime + * | +----- Enabled for wake? + * +-------- + */ +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 1 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 1 +#define ACPI_GPE_EDGE_TRIGGERED (u8) 0 + +#define ACPI_GPE_TYPE_MASK (u8) 2 +#define ACPI_GPE_TYPE_WAKE (u8) 2 +#define ACPI_GPE_TYPE_RUNTIME (u8) 0 /* Default */ + +#define ACPI_GPE_ENABLE_MASK (u8) 4 +#define ACPI_GPE_ENABLED (u8) 4 +#define ACPI_GPE_DISABLED (u8) 0 /* Default */ + +/* + * Flags for GPE and Lock interfaces + */ +#define ACPI_EVENT_WAKE_ENABLE 0x2 +#define ACPI_EVENT_WAKE_DISABLE 0x2 + +#define ACPI_NOT_ISR 0x1 +#define ACPI_ISR 0x0 + /* Notify types */ @@ -794,7 +813,7 @@ #define ACPI_INIT_DEVICE_INI 1 -/* Address Spaces (Operation Regions */ +/* Address Spaces (For Operation Regions) */ typedef acpi_status (*acpi_adr_space_handler) ( @@ -880,7 +899,8 @@ { ACPI_COMMON_OBJ_INFO; - u32 valid; /* Indicates which fields are valid */ + u8 highest_dstates[4]; /* _sx_d values 0xFF indicates not valid */ + u32 valid; /* Indicates which fields below are valid */ u32 current_status; /* _STA value */ acpi_integer address; /* _ADR value if any */ struct acpi_device_id hardware_id; /* _HID value if any */ diff -urN linux-2.4.25/include/acpi/acutils.h linux-2.4.26/include/acpi/acutils.h --- linux-2.4.25/include/acpi/acutils.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/acutils.h 2004-04-14 06:05:40.000000000 -0700 @@ -52,7 +52,6 @@ union acpi_generic_state *state, void *context); - acpi_status acpi_ut_walk_package_tree ( union acpi_operand_object *source_object, @@ -60,7 +59,6 @@ acpi_pkg_callback walk_callback, void *context); - struct acpi_pkg_info { u8 *free_space; @@ -473,9 +471,14 @@ #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__PRW "_PRW" acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state); + +acpi_status acpi_ut_evaluate_object ( struct acpi_namespace_node *prefix_node, char *path, @@ -508,6 +511,10 @@ struct acpi_namespace_node *device_node, struct acpi_device_id *uid); +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest); /* * ut_mutex - mutual exclusion interfaces diff -urN linux-2.4.25/include/acpi/amlcode.h linux-2.4.26/include/acpi/amlcode.h --- linux-2.4.25/include/acpi/amlcode.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/acpi/amlcode.h 2004-04-14 06:05:40.000000000 -0700 @@ -496,11 +496,17 @@ } AML_ACCESS_ATTRIBUTE; -/* bit fields in method_flags byte */ +/* Bit fields in method_flags byte */ -#define METHOD_FLAGS_ARG_COUNT 0x07 -#define METHOD_FLAGS_SERIALIZED 0x08 -#define METHOD_FLAGS_SYNCH_LEVEL 0xF0 +#define AML_METHOD_ARG_COUNT 0x07 +#define AML_METHOD_SERIALIZED 0x08 +#define AML_METHOD_SYNCH_LEVEL 0xF0 + +/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ + +#define AML_METHOD_INTERNAL_ONLY 0x01 +#define AML_METHOD_RESERVED1 0x02 +#define AML_METHOD_RESERVED2 0x04 #endif /* __AMLCODE_H__ */ diff -urN linux-2.4.25/include/asm-i386/acpi.h linux-2.4.26/include/asm-i386/acpi.h --- linux-2.4.25/include/asm-i386/acpi.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-i386/acpi.h 2004-04-14 06:05:40.000000000 -0700 @@ -52,42 +52,36 @@ #define ACPI_ENABLE_IRQS() __sti() #define ACPI_FLUSH_CPU_CACHE() wbinvd() -/* - * A brief explanation as GNU inline assembly is a bit hairy - * %0 is the output parameter in EAX ("=a") - * %1 and %2 are the input parameters in ECX ("c") - * and an immediate value ("i") respectively - * All actual register references are preceded with "%%" as in "%%edx" - * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter are the operation altered non-output registers. - */ + +static inline int +__acpi_acquire_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return (new < 3) ? -1 : 0; +} + +static inline int +__acpi_release_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = old & ~0x3; + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return old & 0x1; +} + #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ - } while(0) + ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr)) #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ - } while(0) - + ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr)) /* * Math helper asm macros @@ -110,6 +104,10 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_strict; +extern int acpi_disabled; +extern int acpi_ht; +static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; } /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 diff -urN linux-2.4.25/include/asm-i386/highmem.h linux-2.4.26/include/asm-i386/highmem.h --- linux-2.4.25/include/asm-i386/highmem.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-i386/highmem.h 2004-04-14 06:05:40.000000000 -0700 @@ -46,7 +46,7 @@ * easily, subsequent pte tables have to be allocated in one physical * chunk of RAM. */ -#define PKMAP_BASE (0xfe000000UL) +#define PKMAP_BASE (0xff800000UL) #ifdef CONFIG_X86_PAE #define LAST_PKMAP 512 #else diff -urN linux-2.4.25/include/asm-i386/mpspec.h linux-2.4.26/include/asm-i386/mpspec.h --- linux-2.4.25/include/asm-i386/mpspec.h 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/include/asm-i386/mpspec.h 2004-04-14 06:05:40.000000000 -0700 @@ -227,10 +227,7 @@ extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base); extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); extern void mp_config_acpi_legacy_irqs (void); -extern void mp_config_ioapic_for_sci(int irq); extern void mp_parse_prt (void); -#else /*!CONFIG_X86_IO_APIC*/ -static inline void mp_config_ioapic_for_sci(int irq) { } #endif /*!CONFIG_X86_IO_APIC*/ #endif /*CONFIG_ACPI_BOOT*/ diff -urN linux-2.4.25/include/asm-i386/system.h linux-2.4.26/include/asm-i386/system.h --- linux-2.4.25/include/asm-i386/system.h 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/include/asm-i386/system.h 2004-04-14 06:05:40.000000000 -0700 @@ -238,6 +238,7 @@ #ifdef CONFIG_X86_CMPXCHG #define __HAVE_ARCH_CMPXCHG 1 +#endif static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) @@ -270,10 +271,6 @@ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ (unsigned long)(n),sizeof(*(ptr)))) -#else -/* Compiling for a 386 proper. Is it worth implementing via cli/sti? */ -#endif - /* * Force strict CPU ordering. * And yes, this is required on UP too when we're talking diff -urN linux-2.4.25/include/asm-ia64/a.out.h linux-2.4.26/include/asm-ia64/a.out.h --- linux-2.4.25/include/asm-ia64/a.out.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/a.out.h 2004-04-14 06:05:40.000000000 -0700 @@ -7,8 +7,8 @@ * probably would be better to clean up binfmt_elf.c so it does not * necessarily depend on there being a.out support. * - * Copyright (C) 1998-2000, 2002 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2000, 2002 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -urN linux-2.4.25/include/asm-ia64/acpi.h linux-2.4.26/include/asm-ia64/acpi.h --- linux-2.4.25/include/asm-ia64/acpi.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/acpi.h 2004-04-14 06:05:40.000000000 -0700 @@ -96,6 +96,10 @@ :"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \ } while (0) +#define acpi_disabled 0 /* ACPI always enabled */ +#define acpi_strict 1 /* no ACPI workarounds */ +static inline void disable_acpi(void) { } + const char *acpi_get_sysname (void); int acpi_request_vector (u32 int_type); int acpi_get_prt (struct pci_vector_struct **vectors, int *count); diff -urN linux-2.4.25/include/asm-ia64/bugs.h linux-2.4.26/include/asm-ia64/bugs.h --- linux-2.4.25/include/asm-ia64/bugs.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/bugs.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,8 +4,10 @@ * Needs: * void check_bugs(void); * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -urN linux-2.4.25/include/asm-ia64/byteorder.h linux-2.4.26/include/asm-ia64/byteorder.h --- linux-2.4.25/include/asm-ia64/byteorder.h 2001-04-05 12:51:47.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/byteorder.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_BYTEORDER_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -urN linux-2.4.25/include/asm-ia64/checksum.h linux-2.4.26/include/asm-ia64/checksum.h --- linux-2.4.25/include/asm-ia64/checksum.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/checksum.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_CHECKSUM_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ /* diff -urN linux-2.4.25/include/asm-ia64/current.h linux-2.4.26/include/asm-ia64/current.h --- linux-2.4.25/include/asm-ia64/current.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/current.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_CURRENT_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ /* In kernel mode, thread pointer (r13) is used to point to the diff -urN linux-2.4.25/include/asm-ia64/errno.h linux-2.4.26/include/asm-ia64/errno.h --- linux-2.4.25/include/asm-ia64/errno.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/errno.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_ERRNO_H /* - * This is derived from the Linux/x86 version. + * Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define EPERM 1 /* Operation not permitted */ diff -urN linux-2.4.25/include/asm-ia64/fcntl.h linux-2.4.26/include/asm-ia64/fcntl.h --- linux-2.4.25/include/asm-ia64/fcntl.h 2000-10-09 17:54:58.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/fcntl.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,10 +1,10 @@ #ifndef _ASM_IA64_FCNTL_H #define _ASM_IA64_FCNTL_H /* - * This is mostly compatible with Linux/x86. + * Based on . * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co. */ /* diff -urN linux-2.4.25/include/asm-ia64/ioctl.h linux-2.4.26/include/asm-ia64/ioctl.h --- linux-2.4.25/include/asm-ia64/ioctl.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/ioctl.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_IOCTL_H /* - * This is mostly derived from the Linux/x86 version. + * Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ /* ioctl command encoding: 32 bits total, command in lower 16 bits, diff -urN linux-2.4.25/include/asm-ia64/ioctls.h linux-2.4.26/include/asm-ia64/ioctls.h --- linux-2.4.25/include/asm-ia64/ioctls.h 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/ioctls.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_IOCTLS_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-ia64/mca.h linux-2.4.26/include/asm-ia64/mca.h --- linux-2.4.25/include/asm-ia64/mca.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/mca.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,7 +2,7 @@ * File: mca.h * Purpose: Machine check handling specific defines * - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2004 Silicon Graphics, Inc. * Copyright (C) Vijay Chander (vijay@engr.sgi.com) * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) */ @@ -17,23 +17,8 @@ #include #include -/* These are the return codes from all the IA64_MCA specific interfaces */ -typedef int ia64_mca_return_code_t; - -enum { - IA64_MCA_SUCCESS = 0, - IA64_MCA_FAILURE = 1 -}; - #define IA64_MCA_RENDEZ_TIMEOUT (20 * 1000) /* value in milliseconds - 20 seconds */ -#define IA64_CMC_INT_DISABLE 0 -#define IA64_CMC_INT_ENABLE 1 - - -typedef u32 int_vector_t; -typedef u64 millisec_t; - typedef union cmcv_reg_u { u64 cmcv_regval; struct { @@ -50,10 +35,6 @@ #define cmcv_mask cmcv_reg_s.cmcr_mask #define cmcv_vector cmcv_reg_s.cmcr_vector - -#define IA64_MCA_UCMC_HANDLER_SIZE 0x10 -#define IA64_INIT_HANDLER_SIZE 0x10 - enum { IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 @@ -82,16 +63,6 @@ } ia64_mc_info_t; -/* Possible rendez states passed from SAL to OS during MCA - * handoff - */ -enum { - IA64_MCA_RENDEZ_NOT_RQD = 0x0, - IA64_MCA_RENDEZ_DONE_WITHOUT_INIT = 0x1, - IA64_MCA_RENDEZ_DONE_WITH_INIT = 0x2, - IA64_MCA_RENDEZ_FAILURE = -1 -}; - typedef struct ia64_mca_sal_to_os_state_s { u64 imsto_os_gp; /* GP of the os registered with the SAL */ u64 imsto_pal_proc; /* PAL_PROC entry point - physical addr */ @@ -133,41 +104,13 @@ */ } ia64_mca_os_to_sal_state_t; -typedef int (*prfunc_t)(const char * fmt, ...); - extern void ia64_mca_init(void); extern void ia64_os_mca_dispatch(void); extern void ia64_os_mca_dispatch_end(void); extern void ia64_mca_ucmc_handler(void); extern void ia64_monarch_init_handler(void); extern void ia64_slave_init_handler(void); -extern void ia64_mca_rendez_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cmc_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cmc_int_caller(int,void *,struct pt_regs *); -extern void ia64_mca_cpe_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cpe_int_caller(int,void *,struct pt_regs *); -extern int ia64_log_print(int,prfunc_t); extern void ia64_mca_cmc_vector_setup(void); -extern int ia64_mca_check_errors(void); - -#define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") -#define platform_mem_dev_err_print ia64_log_prt_oem_data -#define platform_pci_bus_err_print ia64_log_prt_oem_data -#define platform_pci_comp_err_print ia64_log_prt_oem_data -#define platform_plat_specific_err_print ia64_log_prt_oem_data -#define platform_host_ctlr_err_print ia64_log_prt_oem_data -#define platform_plat_bus_err_print ia64_log_prt_oem_data - -#undef MCA_TEST - -#undef IA64_MCA_DEBUG_INFO - -#if defined(IA64_MCA_DEBUG_INFO) -# define IA64_MCA_DEBUG(fmt...) printk(fmt) -#else -# define IA64_MCA_DEBUG(fmt...) -#endif #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_MCA_H */ diff -urN linux-2.4.25/include/asm-ia64/mman.h linux-2.4.26/include/asm-ia64/mman.h --- linux-2.4.25/include/asm-ia64/mman.h 2001-01-04 12:50:17.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/mman.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_MMAN_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #define PROT_READ 0x1 /* page can be read */ diff -urN linux-2.4.25/include/asm-ia64/namei.h linux-2.4.26/include/asm-ia64/namei.h --- linux-2.4.25/include/asm-ia64/namei.h 2001-11-09 14:26:17.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/namei.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_NAMEI_H /* - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998, 1999, 2001 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-ia64/page.h linux-2.4.26/include/asm-ia64/page.h --- linux-2.4.25/include/asm-ia64/page.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/page.h 2004-04-14 06:05:40.000000000 -0700 @@ -120,7 +120,13 @@ #define is_invalid_hugepage_range(addr, len) 0 #endif -#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define ia64_abort() __builtin_trap() +#else +# define ia64_abort() (*(volatile int *) 0 = 0) +#endif + +#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) #define PAGE_BUG(page) do { BUG(); } while (0) static __inline__ int diff -urN linux-2.4.25/include/asm-ia64/param.h linux-2.4.26/include/asm-ia64/param.h --- linux-2.4.25/include/asm-ia64/param.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/param.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,8 +4,10 @@ /* * Fundamental kernel parameters. * - * Copyright (C) 1998, 1999, 2002-2003 Hewlett-Packard Co - * David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999, 2002-2003 + * David Mosberger-Tang , Hewlett-Packard Co */ #define EXEC_PAGESIZE 65536 diff -urN linux-2.4.25/include/asm-ia64/poll.h linux-2.4.26/include/asm-ia64/poll.h --- linux-2.4.25/include/asm-ia64/poll.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/poll.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_POLL_H /* - * poll(2) bit definitions. Chosen to be compatible with Linux/x86. + * poll(2) bit definitions. Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define POLLIN 0x0001 diff -urN linux-2.4.25/include/asm-ia64/posix_types.h linux-2.4.26/include/asm-ia64/posix_types.h --- linux-2.4.25/include/asm-ia64/posix_types.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/posix_types.h 2004-04-14 06:05:40.000000000 -0700 @@ -6,8 +6,10 @@ * be a little careful about namespace pollution etc. Also, we cannot * assume GCC is being used. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ typedef unsigned int __kernel_dev_t; diff -urN linux-2.4.25/include/asm-ia64/processor.h linux-2.4.26/include/asm-ia64/processor.h --- linux-2.4.25/include/asm-ia64/processor.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/processor.h 2004-04-14 06:05:40.000000000 -0700 @@ -927,24 +927,13 @@ return retval; } -/* XXX remove the handcoded version once we have a sufficiently clever compiler... */ -#ifdef SMART_COMPILER -# define ia64_rotr(w,n) \ - ({ \ - __u64 _w = (w), _n = (n); \ - \ - (_w >> _n) | (_w << (64 - _n)); \ - }) -#else -# define ia64_rotr(w,n) \ - ({ \ - __u64 result; \ - asm ("shrp %0=%1,%1,%2" : "=r"(result) : "r"(w), "i"(n)); \ - result; \ - }) -#endif +static inline __u64 +ia64_rotr (__u64 w, __u64 n) +{ + return (w >> n) | (w << (64 - n)); +} -#define ia64_rotl(w,n) ia64_rotr((w),(64)-(n)) +#define ia64_rotl(w,n) ia64_rotr((w), (64) - (n)) static inline __u64 ia64_thash (__u64 addr) diff -urN linux-2.4.25/include/asm-ia64/resource.h linux-2.4.26/include/asm-ia64/resource.h --- linux-2.4.25/include/asm-ia64/resource.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/resource.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,8 +4,10 @@ /* * Resource limits * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-ia64/scatterlist.h linux-2.4.26/include/asm-ia64/scatterlist.h --- linux-2.4.25/include/asm-ia64/scatterlist.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/scatterlist.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_SCATTERLIST_H /* - * Copyright (C) 1998-1999, 2001-2002 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-1999, 2001-2002 + * David Mosberger-Tang , Hewlett-Packard Co */ struct scatterlist { diff -urN linux-2.4.25/include/asm-ia64/siginfo.h linux-2.4.26/include/asm-ia64/siginfo.h --- linux-2.4.25/include/asm-ia64/siginfo.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/siginfo.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_SIGINFO_H /* - * Copyright (C) 1998-2002 Hewlett-Packard Co - * David Mosberger-Tang + * Based on . + * + * Modified 1998-2002 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-ia64/signal.h linux-2.4.26/include/asm-ia64/signal.h --- linux-2.4.25/include/asm-ia64/signal.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/signal.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_SIGNAL_H /* - * Copyright (C) 1998-2001 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2001 + * David Mosberger-Tang , Hewlett-Packard Co * * Unfortunately, this file is being included by bits/signal.h in * glibc-2.x. Hence the #ifdef __KERNEL__ ugliness. diff -urN linux-2.4.25/include/asm-ia64/socket.h linux-2.4.26/include/asm-ia64/socket.h --- linux-2.4.25/include/asm-ia64/socket.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/socket.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,10 +2,12 @@ #define _ASM_IA64_SOCKET_H /* - * Socket related defines. This mostly mirrors the Linux/x86 version. + * Socket related defines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-ia64/sockios.h linux-2.4.26/include/asm-ia64/sockios.h --- linux-2.4.25/include/asm-ia64/sockios.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/sockios.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,11 +2,12 @@ #define _ASM_IA64_SOCKIOS_H /* - * Socket-level I/O control calls. This mostly mirrors the Linux/x86 - * version. + * Socket-level I/O control calls. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define FIOSETOWN 0x8901 #define SIOCSPGRP 0x8902 diff -urN linux-2.4.25/include/asm-ia64/stat.h linux-2.4.26/include/asm-ia64/stat.h --- linux-2.4.25/include/asm-ia64/stat.h 2000-06-22 07:09:45.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/stat.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_STAT_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ struct stat { diff -urN linux-2.4.25/include/asm-ia64/statfs.h linux-2.4.26/include/asm-ia64/statfs.h --- linux-2.4.25/include/asm-ia64/statfs.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/statfs.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_STATFS_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ # ifndef __KERNEL_STRICT_NAMES diff -urN linux-2.4.25/include/asm-ia64/termbits.h linux-2.4.26/include/asm-ia64/termbits.h --- linux-2.4.25/include/asm-ia64/termbits.h 2000-02-06 18:42:40.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/termbits.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_TERMBITS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Based on . + * + * Modified 1999 + * David Mosberger-Tang , Hewlett-Packard Co * * 99/01/28 Added new baudrates */ diff -urN linux-2.4.25/include/asm-ia64/termios.h linux-2.4.26/include/asm-ia64/termios.h --- linux-2.4.25/include/asm-ia64/termios.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/termios.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_TERMIOS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Modified 1999 + * David Mosberger-Tang , Hewlett-Packard Co * * 99/01/28 Added N_IRDA and N_SMSBLOCK */ diff -urN linux-2.4.25/include/asm-ia64/types.h linux-2.4.26/include/asm-ia64/types.h --- linux-2.4.25/include/asm-ia64/types.h 2000-04-21 15:21:24.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/types.h 2004-04-14 06:05:40.000000000 -0700 @@ -8,8 +8,10 @@ * not a major issue. However, for interoperability, libraries still * need to be careful to avoid a name clashes. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #ifdef __ASSEMBLY__ diff -urN linux-2.4.25/include/asm-ia64/uaccess.h linux-2.4.26/include/asm-ia64/uaccess.h --- linux-2.4.25/include/asm-ia64/uaccess.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/uaccess.h 2004-04-14 06:05:40.000000000 -0700 @@ -26,6 +26,8 @@ * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and * then resumes execution at the continuation point. * + * Based on . + * * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co * David Mosberger-Tang */ diff -urN linux-2.4.25/include/asm-ia64/unaligned.h linux-2.4.26/include/asm-ia64/unaligned.h --- linux-2.4.25/include/asm-ia64/unaligned.h 2003-08-25 04:44:43.000000000 -0700 +++ linux-2.4.26/include/asm-ia64/unaligned.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,8 +4,9 @@ #include /* - * The main single-value unaligned transfer routines. Derived from - * the Linux/Alpha version. + * The main single-value unaligned transfer routines. + * + * Based on . * * Copyright (C) 1998, 1999, 2003 Hewlett-Packard Co * David Mosberger-Tang diff -urN linux-2.4.25/include/asm-ia64/unwind.h linux-2.4.26/include/asm-ia64/unwind.h --- linux-2.4.25/include/asm-ia64/unwind.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/unwind.h 2004-04-14 06:05:40.000000000 -0700 @@ -93,6 +93,12 @@ * The official API follows below: */ +struct unw_table_entry { + u64 start_offset; + u64 end_offset; + u64 info_offset; +}; + /* * Initialize unwind support. */ diff -urN linux-2.4.25/include/asm-ia64/user.h linux-2.4.26/include/asm-ia64/user.h --- linux-2.4.25/include/asm-ia64/user.h 2001-11-09 14:26:17.000000000 -0800 +++ linux-2.4.26/include/asm-ia64/user.h 2004-04-14 06:05:40.000000000 -0700 @@ -24,8 +24,8 @@ * current->start_stack, so we round each of these in order to be able * to write an integer number of pages. * - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang + * Modified 1998, 1999, 2001 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -urN linux-2.4.25/include/asm-m68k/keyboard.h linux-2.4.26/include/asm-m68k/keyboard.h --- linux-2.4.25/include/asm-m68k/keyboard.h 2001-08-12 11:13:59.000000000 -0700 +++ linux-2.4.26/include/asm-m68k/keyboard.h 2004-04-14 06:05:40.000000000 -0700 @@ -65,6 +65,11 @@ #define kbd_request_region() #define kbd_request_irq(handler) +/* How to access the keyboard macros on this platform. */ +#define kbd_read_input() in_8(KBD_DATA_REG) +#define kbd_read_status() in_8(KBD_STATUS_REG) +#define kbd_write_output(val) out_8(KBD_DATA_REG, val) +#define kbd_write_command(val) out_8(KBD_CNTL_REG, val) extern unsigned int SYSRQ_KEY; #endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/asm-ppc/cpm2.h linux-2.4.26/include/asm-ppc/cpm2.h --- linux-2.4.25/include/asm-ppc/cpm2.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/cpm2.h 2004-04-14 06:05:40.000000000 -0700 @@ -0,0 +1,1037 @@ +/* + * Communication Processor Module v2. + * + * This file contains structures and information for the communication + * processor channels found in the dual port RAM or parameter RAM. + * All CPM control and status is available through the CPM2 internal + * memory map. See immap_cpm2.h for details. + */ +#ifdef __KERNEL__ +#ifndef __CPM2__ +#define __CPM2__ + +#include + +/* CPM Command register. +*/ +#define CPM_CR_RST ((uint)0x80000000) +#define CPM_CR_PAGE ((uint)0x7c000000) +#define CPM_CR_SBLOCK ((uint)0x03e00000) +#define CPM_CR_FLG ((uint)0x00010000) +#define CPM_CR_MCN ((uint)0x00003fc0) +#define CPM_CR_OPCODE ((uint)0x0000000f) + +/* Device sub-block and page codes. +*/ +#define CPM_CR_SCC1_SBLOCK (0x04) +#define CPM_CR_SCC2_SBLOCK (0x05) +#define CPM_CR_SCC3_SBLOCK (0x06) +#define CPM_CR_SCC4_SBLOCK (0x07) +#define CPM_CR_SMC1_SBLOCK (0x08) +#define CPM_CR_SMC2_SBLOCK (0x09) +#define CPM_CR_SPI_SBLOCK (0x0a) +#define CPM_CR_I2C_SBLOCK (0x0b) +#define CPM_CR_TIMER_SBLOCK (0x0f) +#define CPM_CR_RAND_SBLOCK (0x0e) +#define CPM_CR_FCC1_SBLOCK (0x10) +#define CPM_CR_FCC2_SBLOCK (0x11) +#define CPM_CR_FCC3_SBLOCK (0x12) +#define CPM_CR_IDMA1_SBLOCK (0x14) +#define CPM_CR_IDMA2_SBLOCK (0x15) +#define CPM_CR_IDMA3_SBLOCK (0x16) +#define CPM_CR_IDMA4_SBLOCK (0x17) +#define CPM_CR_MCC1_SBLOCK (0x1c) + +#define CPM_CR_SCC1_PAGE (0x00) +#define CPM_CR_SCC2_PAGE (0x01) +#define CPM_CR_SCC3_PAGE (0x02) +#define CPM_CR_SCC4_PAGE (0x03) +#define CPM_CR_SMC1_PAGE (0x07) +#define CPM_CR_SMC2_PAGE (0x08) +#define CPM_CR_SPI_PAGE (0x09) +#define CPM_CR_I2C_PAGE (0x0a) +#define CPM_CR_TIMER_PAGE (0x0a) +#define CPM_CR_RAND_PAGE (0x0a) +#define CPM_CR_FCC1_PAGE (0x04) +#define CPM_CR_FCC2_PAGE (0x05) +#define CPM_CR_FCC3_PAGE (0x06) +#define CPM_CR_IDMA1_PAGE (0x07) +#define CPM_CR_IDMA2_PAGE (0x08) +#define CPM_CR_IDMA3_PAGE (0x09) +#define CPM_CR_IDMA4_PAGE (0x0a) +#define CPM_CR_MCC1_PAGE (0x07) +#define CPM_CR_MCC2_PAGE (0x08) + +/* Some opcodes (there are more...later) +*/ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_START_IDMA ((ushort)0x0009) +#define CPM_CR_STOP_IDMA ((ushort)0x000b) + +#define mk_cr_cmd(PG, SBC, MCN, OP) \ + ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) + +/* Dual Port RAM addresses. The first 16K is available for almost + * any CPM use, so we put the BDs there. The first 128 bytes are + * used for SMC1 and SMC2 parameter RAM, so we start allocating + * BDs above that. All of this must change when we start + * downloading RAM microcode. + */ +#define CPM_DATAONLY_BASE ((uint)128) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) +#ifdef CONFIG_8272 +#define CPM_DATAONLY_SIZE ((uint)(8 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x00009000) +#else +#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) +#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) +#endif + +/* The number of pages of host memory we allocate for CPM. This is + * done early in kernel initialization to get physically contiguous + * pages. + */ +#define NUM_CPM_HOST_PAGES 2 + + +/* Export the base address of the communication processor registers + * and dual port ram. + */ +extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */ +uint cpm2_dpalloc(uint size, uint align); +uint cpm2_hostalloc(uint size, uint align); +void cpm2_setbrg(uint brg, uint rate); +void cpm2_fastbrg(uint brg, uint rate, int div16); + +/* Buffer descriptors used by many of the CPM protocols. +*/ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; + +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ + +/* Function code bits, usually generic to devices. +*/ +#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ +#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ +#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ +#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ +#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ + +/* Parameter RAM offsets from the base. +*/ +#define PROFF_SCC1 ((uint)0x8000) +#define PROFF_SCC2 ((uint)0x8100) +#define PROFF_SCC3 ((uint)0x8200) +#define PROFF_SCC4 ((uint)0x8300) +#define PROFF_FCC1 ((uint)0x8400) +#define PROFF_FCC2 ((uint)0x8500) +#define PROFF_FCC3 ((uint)0x8600) +#define PROFF_MCC1 ((uint)0x8700) +#define PROFF_SMC1_BASE ((uint)0x87fc) +#define PROFF_IDMA1_BASE ((uint)0x87fe) +#define PROFF_MCC2 ((uint)0x8800) +#define PROFF_SMC2_BASE ((uint)0x88fc) +#define PROFF_IDMA2_BASE ((uint)0x88fe) +#define PROFF_SPI_BASE ((uint)0x89fc) +#define PROFF_IDMA3_BASE ((uint)0x89fe) +#define PROFF_TIMERS ((uint)0x8ae0) +#define PROFF_REVNUM ((uint)0x8af0) +#define PROFF_RAND ((uint)0x8af8) +#define PROFF_I2C_BASE ((uint)0x8afc) +#define PROFF_IDMA4_BASE ((uint)0x8afe) + +/* The SMCs are relocated to any of the first eight DPRAM pages. + * We will fix these at the first locations of DPRAM, until we + * get some microcode patches :-). + * The parameter ram space for the SMCs is fifty-some bytes, and + * they are required to start on a 64 byte boundary. + */ +#define PROFF_SMC1 (0) +#define PROFF_SMC2 (64) + + +/* Define enough so I can at least use the serial port as a UART. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ + uint smc_stmp; /* SDMA Temp */ +} smc_uart_t; + +/* SMC uart mode register (Internal memory map). +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + +/* CPM Ethernet through SCC1. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PSMR) as used by Ethernet. +*/ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. + * Common to SCC and FCC. + */ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. + * Common to SCC and FCC. + */ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PSMR when used as a UART. +*/ +#define SCU_PSMR_FLC ((ushort)0x8000) +#define SCU_PSMR_SL ((ushort)0x4000) +#define SCU_PSMR_CL ((ushort)0x3000) +#define SCU_PSMR_UM ((ushort)0x0c00) +#define SCU_PSMR_FRZ ((ushort)0x0200) +#define SCU_PSMR_RZS ((ushort)0x0100) +#define SCU_PSMR_SYN ((ushort)0x0080) +#define SCU_PSMR_DRT ((ushort)0x0040) +#define SCU_PSMR_PEN ((ushort)0x0010) +#define SCU_PSMR_RPM ((ushort)0x000c) +#define SCU_PSMR_REVP ((ushort)0x0008) +#define SCU_PSMR_TPM ((ushort)0x0003) +#define SCU_PSMR_TEVP ((ushort)0x0003) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + +/* How about some FCCs..... +*/ +#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) +#define FCC_GFMR_DIAG_LE ((uint)0x40000000) +#define FCC_GFMR_DIAG_AE ((uint)0x80000000) +#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) +#define FCC_GFMR_TCI ((uint)0x20000000) +#define FCC_GFMR_TRX ((uint)0x10000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_CDP ((uint)0x04000000) +#define FCC_GFMR_CTSP ((uint)0x02000000) +#define FCC_GFMR_CDS ((uint)0x01000000) +#define FCC_GFMR_CTSS ((uint)0x00800000) +#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) +#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) +#define FCC_GFMR_SYNL_8 ((uint)0x00008000) +#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) +#define FCC_GFMR_RTSM ((uint)0x00002000) +#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) +#define FCC_GFMR_REVD ((uint)0x00000400) +#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) +#define FCC_GFMR_TCRC_16 ((uint)0x00000000) +#define FCC_GFMR_TCRC_32 ((uint)0x00000080) +#define FCC_GFMR_ENR ((uint)0x00000020) +#define FCC_GFMR_ENT ((uint)0x00000010) +#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) +#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) +#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) + +/* Generic FCC parameter ram. +*/ +typedef struct fcc_param { + ushort fcc_riptr; /* Rx Internal temp pointer */ + ushort fcc_tiptr; /* Tx Internal temp pointer */ + ushort fcc_res1; + ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ + uint fcc_rstate; /* Upper byte is Func code, must be set */ + uint fcc_rbase; /* Receive BD base */ + ushort fcc_rbdstat; /* RxBD status */ + ushort fcc_rbdlen; /* RxBD down counter */ + uint fcc_rdptr; /* RxBD internal data pointer */ + uint fcc_tstate; /* Upper byte is Func code, must be set */ + uint fcc_tbase; /* Transmit BD base */ + ushort fcc_tbdstat; /* TxBD status */ + ushort fcc_tbdlen; /* TxBD down counter */ + uint fcc_tdptr; /* TxBD internal data pointer */ + uint fcc_rbptr; /* Rx BD Internal buf pointer */ + uint fcc_tbptr; /* Tx BD Internal buf pointer */ + uint fcc_rcrc; /* Rx temp CRC */ + uint fcc_res2; + uint fcc_tcrc; /* Tx temp CRC */ +} fccp_t; + + +/* Ethernet controller through FCC. +*/ +typedef struct fcc_enet { + fccp_t fen_genfcc; + uint fen_statbuf; /* Internal status buffer */ + uint fen_camptr; /* CAM address */ + uint fen_cmask; /* Constant mask for CRC */ + uint fen_cpres; /* Preset CRC */ + uint fen_crcec; /* CRC Error counter */ + uint fen_alec; /* alignment error counter */ + uint fen_disfc; /* discard frame counter */ + ushort fen_retlim; /* Retry limit */ + ushort fen_retcnt; /* Retry counter */ + ushort fen_pper; /* Persistence */ + ushort fen_boffcnt; /* backoff counter */ + uint fen_gaddrh; /* Group address filter, high 32-bits */ + uint fen_gaddrl; /* Group address filter, low 32-bits */ + ushort fen_tfcstat; /* out of sequence TxBD */ + ushort fen_tfclen; + uint fen_tfcptr; + ushort fen_mflr; /* Maximum frame length (1518) */ + ushort fen_paddrh; /* MAC address */ + ushort fen_paddrm; + ushort fen_paddrl; + ushort fen_ibdcount; /* Internal BD counter */ + ushort fen_ibdstart; /* Internal BD start pointer */ + ushort fen_ibdend; /* Internal BD end pointer */ + ushort fen_txlen; /* Internal Tx frame length counter */ + uint fen_ibdbase[8]; /* Internal use */ + uint fen_iaddrh; /* Individual address filter */ + uint fen_iaddrl; + ushort fen_minflr; /* Minimum frame length (64) */ + ushort fen_taddrh; /* Filter transfer MAC address */ + ushort fen_taddrm; + ushort fen_taddrl; + ushort fen_padptr; /* Pointer to pad byte buffer */ + ushort fen_cftype; /* control frame type */ + ushort fen_cfrange; /* control frame range */ + ushort fen_maxb; /* maximum BD count */ + ushort fen_maxd1; /* Max DMA1 length (1520) */ + ushort fen_maxd2; /* Max DMA2 length (1520) */ + ushort fen_maxd; /* internal max DMA count */ + ushort fen_dmacnt; /* internal DMA counter */ + uint fen_octc; /* Total octect counter */ + uint fen_colc; /* Total collision counter */ + uint fen_broc; /* Total broadcast packet counter */ + uint fen_mulc; /* Total multicast packet count */ + uint fen_uspc; /* Total packets < 64 bytes */ + uint fen_frgc; /* Total packets < 64 bytes with errors */ + uint fen_ospc; /* Total packets > 1518 */ + uint fen_jbrc; /* Total packets > 1518 with errors */ + uint fen_p64c; /* Total packets == 64 bytes */ + uint fen_p65c; /* Total packets 64 < bytes <= 127 */ + uint fen_p128c; /* Total packets 127 < bytes <= 255 */ + uint fen_p256c; /* Total packets 256 < bytes <= 511 */ + uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ + uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ + uint fen_cambuf; /* Internal CAM buffer poiner */ + ushort fen_rfthr; /* Received frames threshold */ + ushort fen_rfcnt; /* Received frames count */ +} fcc_enet_t; + +/* FCC Event/Mask register as used by Ethernet. +*/ +#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ +#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ +#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ +#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* FCC Mode Register (FPSMR) as used by Ethernet. +*/ +#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ +#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ +#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ +#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ +#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ +#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ +#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ +#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ +#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ +#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ +#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ +#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ +#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ + +/* IIC parameter RAM. +*/ +typedef struct iic { + ushort iic_rbase; /* Rx Buffer descriptor base address */ + ushort iic_tbase; /* Tx Buffer descriptor base address */ + u_char iic_rfcr; /* Rx function code */ + u_char iic_tfcr; /* Tx function code */ + ushort iic_mrblr; /* Max receive buffer length */ + uint iic_rstate; /* Internal */ + uint iic_rdp; /* Internal */ + ushort iic_rbptr; /* Internal */ + ushort iic_rbc; /* Internal */ + uint iic_rxtmp; /* Internal */ + uint iic_tstate; /* Internal */ + uint iic_tdp; /* Internal */ + ushort iic_tbptr; /* Internal */ + ushort iic_tbc; /* Internal */ + uint iic_txtmp; /* Internal */ +} iic_t; + +/* SPI parameter RAM. +*/ +typedef struct spi { + ushort spi_rbase; /* Rx Buffer descriptor base address */ + ushort spi_tbase; /* Tx Buffer descriptor base address */ + u_char spi_rfcr; /* Rx function code */ + u_char spi_tfcr; /* Tx function code */ + ushort spi_mrblr; /* Max receive buffer length */ + uint spi_rstate; /* Internal */ + uint spi_rdp; /* Internal */ + ushort spi_rbptr; /* Internal */ + ushort spi_rbc; /* Internal */ + uint spi_rxtmp; /* Internal */ + uint spi_tstate; /* Internal */ + uint spi_tdp; /* Internal */ + ushort spi_tbptr; /* Internal */ + ushort spi_tbc; /* Internal */ + uint spi_txtmp; /* Internal */ + uint spi_res; /* Tx temp. */ + uint spi_res1[4]; /* SDMA temp. */ +} spi_t; + +/* SPI Mode register. +*/ +#define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ +#define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ +#define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ +#define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ +#define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ +#define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ +#define SPMODE_EN ((ushort)0x0100) /* Enable */ +#define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ +#define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ + +#define SPMODE_LEN(x) ((((x)-1)&0xF)<<4) +#define SPMODE_PM(x) ((x) &0xF) + +#define SPI_EB ((u_char)0x10) /* big endian byte order */ + +#define BD_IIC_START ((ushort)0x0400) + +/* IDMA parameter RAM +*/ +typedef struct idma { + ushort ibase; /* IDMA buffer descriptor table base address */ + ushort dcm; /* DMA channel mode */ + ushort ibdptr; /* IDMA current buffer descriptor pointer */ + ushort dpr_buf; /* IDMA transfer buffer base address */ + ushort buf_inv; /* internal buffer inventory */ + ushort ss_max; /* steady-state maximum transfer size */ + ushort dpr_in_ptr; /* write pointer inside the internal buffer */ + ushort sts; /* source transfer size */ + ushort dpr_out_ptr; /* read pointer inside the internal buffer */ + ushort seob; /* source end of burst */ + ushort deob; /* destination end of burst */ + ushort dts; /* destination transfer size */ + ushort ret_add; /* return address when working in ERM=1 mode */ + ushort res0; /* reserved */ + uint bd_cnt; /* internal byte count */ + uint s_ptr; /* source internal data pointer */ + uint d_ptr; /* destination internal data pointer */ + uint istate; /* internal state */ + u_char res1[20]; /* pad to 64-byte length */ +} idma_t; + +/* DMA channel mode bit fields +*/ +#define IDMA_DCM_FB ((ushort)0x8000) /* fly-by mode */ +#define IDMA_DCM_LP ((ushort)0x4000) /* low priority */ +#define IDMA_DCM_TC2 ((ushort)0x0400) /* value driven on TC[2] */ +#define IDMA_DCM_DMA_WRAP_MASK ((ushort)0x01c0) /* mask for DMA wrap */ +#define IDMA_DCM_DMA_WRAP_64 ((ushort)0x0000) /* 64-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_128 ((ushort)0x0040) /* 128-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_256 ((ushort)0x0080) /* 256-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_512 ((ushort)0x00c0) /* 512-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_1024 ((ushort)0x0100) /* 1024-byte DMA xfer buffer */ +#define IDMA_DCM_DMA_WRAP_2048 ((ushort)0x0140) /* 2048-byte DMA xfer buffer */ +#define IDMA_DCM_SINC ((ushort)0x0020) /* source inc addr */ +#define IDMA_DCM_DINC ((ushort)0x0010) /* destination inc addr */ +#define IDMA_DCM_ERM ((ushort)0x0008) /* external request mode */ +#define IDMA_DCM_DT ((ushort)0x0004) /* DONE treatment */ +#define IDMA_DCM_SD_MASK ((ushort)0x0003) /* mask for SD bit field */ +#define IDMA_DCM_SD_MEM2MEM ((ushort)0x0000) /* memory-to-memory xfer */ +#define IDMA_DCM_SD_PER2MEM ((ushort)0x0002) /* peripheral-to-memory xfer */ +#define IDMA_DCM_SD_MEM2PER ((ushort)0x0001) /* memory-to-peripheral xfer */ + +/* IDMA Buffer Descriptors +*/ +typedef struct idma_bd { + uint flags; + uint len; /* data length */ + uint src; /* source data buffer pointer */ + uint dst; /* destination data buffer pointer */ +} idma_bd_t; + +/* IDMA buffer descriptor flag bit fields +*/ +#define IDMA_BD_V ((uint)0x80000000) /* valid */ +#define IDMA_BD_W ((uint)0x20000000) /* wrap */ +#define IDMA_BD_I ((uint)0x10000000) /* interrupt */ +#define IDMA_BD_L ((uint)0x08000000) /* last */ +#define IDMA_BD_CM ((uint)0x02000000) /* continuous mode */ +#define IDMA_BD_SDN ((uint)0x00400000) /* source done */ +#define IDMA_BD_DDN ((uint)0x00200000) /* destination done */ +#define IDMA_BD_DGBL ((uint)0x00100000) /* destination global */ +#define IDMA_BD_DBO_LE ((uint)0x00040000) /* little-end dest byte order */ +#define IDMA_BD_DBO_BE ((uint)0x00080000) /* big-end dest byte order */ +#define IDMA_BD_DDTB ((uint)0x00010000) /* destination data bus */ +#define IDMA_BD_SGBL ((uint)0x00002000) /* source global */ +#define IDMA_BD_SBO_LE ((uint)0x00000800) /* little-end src byte order */ +#define IDMA_BD_SBO_BE ((uint)0x00001000) /* big-end src byte order */ +#define IDMA_BD_SDTB ((uint)0x00000200) /* source data bus */ + +/* per-channel IDMA registers +*/ +typedef struct im_idma { + u_char idsr; /* IDMAn event status register */ + u_char res0[3]; + u_char idmr; /* IDMAn event mask register */ + u_char res1[3]; +} im_idma_t; + +/* IDMA event register bit fields +*/ +#define IDMA_EVENT_SC ((unsigned char)0x08) /* stop completed */ +#define IDMA_EVENT_OB ((unsigned char)0x04) /* out of buffers */ +#define IDMA_EVENT_EDN ((unsigned char)0x02) /* external DONE asserted */ +#define IDMA_EVENT_BC ((unsigned char)0x01) /* buffer descriptor complete */ + +/* RISC Controller Configuration Register (RCCR) bit fields +*/ +#define RCCR_TIME ((uint)0x80000000) /* timer enable */ +#define RCCR_TIMEP_MASK ((uint)0x3f000000) /* mask for timer period bit field */ +#define RCCR_DR0M ((uint)0x00800000) /* IDMA0 request mode */ +#define RCCR_DR1M ((uint)0x00400000) /* IDMA1 request mode */ +#define RCCR_DR2M ((uint)0x00000080) /* IDMA2 request mode */ +#define RCCR_DR3M ((uint)0x00000040) /* IDMA3 request mode */ +#define RCCR_DR0QP_MASK ((uint)0x00300000) /* mask for IDMA0 req priority */ +#define RCCR_DR0QP_HIGH ((uint)0x00000000) /* IDMA0 has high req priority */ +#define RCCR_DR0QP_MED ((uint)0x00100000) /* IDMA0 has medium req priority */ +#define RCCR_DR0QP_LOW ((uint)0x00200000) /* IDMA0 has low req priority */ +#define RCCR_DR1QP_MASK ((uint)0x00030000) /* mask for IDMA1 req priority */ +#define RCCR_DR1QP_HIGH ((uint)0x00000000) /* IDMA1 has high req priority */ +#define RCCR_DR1QP_MED ((uint)0x00010000) /* IDMA1 has medium req priority */ +#define RCCR_DR1QP_LOW ((uint)0x00020000) /* IDMA1 has low req priority */ +#define RCCR_DR2QP_MASK ((uint)0x00000030) /* mask for IDMA2 req priority */ +#define RCCR_DR2QP_HIGH ((uint)0x00000000) /* IDMA2 has high req priority */ +#define RCCR_DR2QP_MED ((uint)0x00000010) /* IDMA2 has medium req priority */ +#define RCCR_DR2QP_LOW ((uint)0x00000020) /* IDMA2 has low req priority */ +#define RCCR_DR3QP_MASK ((uint)0x00000003) /* mask for IDMA3 req priority */ +#define RCCR_DR3QP_HIGH ((uint)0x00000000) /* IDMA3 has high req priority */ +#define RCCR_DR3QP_MED ((uint)0x00000001) /* IDMA3 has medium req priority */ +#define RCCR_DR3QP_LOW ((uint)0x00000002) /* IDMA3 has low req priority */ +#define RCCR_EIE ((uint)0x00080000) /* external interrupt enable */ +#define RCCR_SCD ((uint)0x00040000) /* scheduler configuration */ +#define RCCR_ERAM_MASK ((uint)0x0000e000) /* mask for enable RAM microcode */ +#define RCCR_ERAM_0KB ((uint)0x00000000) /* use 0KB of dpram for microcode */ +#define RCCR_ERAM_2KB ((uint)0x00002000) /* use 2KB of dpram for microcode */ +#define RCCR_ERAM_4KB ((uint)0x00004000) /* use 4KB of dpram for microcode */ +#define RCCR_ERAM_6KB ((uint)0x00006000) /* use 6KB of dpram for microcode */ +#define RCCR_ERAM_8KB ((uint)0x00008000) /* use 8KB of dpram for microcode */ +#define RCCR_ERAM_10KB ((uint)0x0000a000) /* use 10KB of dpram for microcode */ +#define RCCR_ERAM_12KB ((uint)0x0000c000) /* use 12KB of dpram for microcode */ +#define RCCR_EDM0 ((uint)0x00000800) /* DREQ0 edge detect mode */ +#define RCCR_EDM1 ((uint)0x00000400) /* DREQ1 edge detect mode */ +#define RCCR_EDM2 ((uint)0x00000200) /* DREQ2 edge detect mode */ +#define RCCR_EDM3 ((uint)0x00000100) /* DREQ3 edge detect mode */ +#define RCCR_DEM01 ((uint)0x00000008) /* DONE0/DONE1 edge detect mode */ +#define RCCR_DEM23 ((uint)0x00000004) /* DONE2/DONE3 edge detect mode */ + +/*----------------------------------------------------------------------- + * CMXFCR - CMX FCC Clock Route Register + */ +#define CMXFCR_FC1 0x40000000 /* FCC1 connection */ +#define CMXFCR_RF1CS_MSK 0x38000000 /* Receive FCC1 Clock Source Mask */ +#define CMXFCR_TF1CS_MSK 0x07000000 /* Transmit FCC1 Clock Source Mask */ +#define CMXFCR_FC2 0x00400000 /* FCC2 connection */ +#define CMXFCR_RF2CS_MSK 0x00380000 /* Receive FCC2 Clock Source Mask */ +#define CMXFCR_TF2CS_MSK 0x00070000 /* Transmit FCC2 Clock Source Mask */ +#define CMXFCR_FC3 0x00004000 /* FCC3 connection */ +#define CMXFCR_RF3CS_MSK 0x00003800 /* Receive FCC3 Clock Source Mask */ +#define CMXFCR_TF3CS_MSK 0x00000700 /* Transmit FCC3 Clock Source Mask */ + +#define CMXFCR_RF1CS_BRG5 0x00000000 /* Receive FCC1 Clock Source is BRG5 */ +#define CMXFCR_RF1CS_BRG6 0x08000000 /* Receive FCC1 Clock Source is BRG6 */ +#define CMXFCR_RF1CS_BRG7 0x10000000 /* Receive FCC1 Clock Source is BRG7 */ +#define CMXFCR_RF1CS_BRG8 0x18000000 /* Receive FCC1 Clock Source is BRG8 */ +#define CMXFCR_RF1CS_CLK9 0x20000000 /* Receive FCC1 Clock Source is CLK9 */ +#define CMXFCR_RF1CS_CLK10 0x28000000 /* Receive FCC1 Clock Source is CLK10 */ +#define CMXFCR_RF1CS_CLK11 0x30000000 /* Receive FCC1 Clock Source is CLK11 */ +#define CMXFCR_RF1CS_CLK12 0x38000000 /* Receive FCC1 Clock Source is CLK12 */ + +#define CMXFCR_TF1CS_BRG5 0x00000000 /* Transmit FCC1 Clock Source is BRG5 */ +#define CMXFCR_TF1CS_BRG6 0x01000000 /* Transmit FCC1 Clock Source is BRG6 */ +#define CMXFCR_TF1CS_BRG7 0x02000000 /* Transmit FCC1 Clock Source is BRG7 */ +#define CMXFCR_TF1CS_BRG8 0x03000000 /* Transmit FCC1 Clock Source is BRG8 */ +#define CMXFCR_TF1CS_CLK9 0x04000000 /* Transmit FCC1 Clock Source is CLK9 */ +#define CMXFCR_TF1CS_CLK10 0x05000000 /* Transmit FCC1 Clock Source is CLK10 */ +#define CMXFCR_TF1CS_CLK11 0x06000000 /* Transmit FCC1 Clock Source is CLK11 */ +#define CMXFCR_TF1CS_CLK12 0x07000000 /* Transmit FCC1 Clock Source is CLK12 */ + +#define CMXFCR_RF2CS_BRG5 0x00000000 /* Receive FCC2 Clock Source is BRG5 */ +#define CMXFCR_RF2CS_BRG6 0x00080000 /* Receive FCC2 Clock Source is BRG6 */ +#define CMXFCR_RF2CS_BRG7 0x00100000 /* Receive FCC2 Clock Source is BRG7 */ +#define CMXFCR_RF2CS_BRG8 0x00180000 /* Receive FCC2 Clock Source is BRG8 */ +#define CMXFCR_RF2CS_CLK13 0x00200000 /* Receive FCC2 Clock Source is CLK13 */ +#define CMXFCR_RF2CS_CLK14 0x00280000 /* Receive FCC2 Clock Source is CLK14 */ +#define CMXFCR_RF2CS_CLK15 0x00300000 /* Receive FCC2 Clock Source is CLK15 */ +#define CMXFCR_RF2CS_CLK16 0x00380000 /* Receive FCC2 Clock Source is CLK16 */ + +#define CMXFCR_TF2CS_BRG5 0x00000000 /* Transmit FCC2 Clock Source is BRG5 */ +#define CMXFCR_TF2CS_BRG6 0x00010000 /* Transmit FCC2 Clock Source is BRG6 */ +#define CMXFCR_TF2CS_BRG7 0x00020000 /* Transmit FCC2 Clock Source is BRG7 */ +#define CMXFCR_TF2CS_BRG8 0x00030000 /* Transmit FCC2 Clock Source is BRG8 */ +#define CMXFCR_TF2CS_CLK13 0x00040000 /* Transmit FCC2 Clock Source is CLK13 */ +#define CMXFCR_TF2CS_CLK14 0x00050000 /* Transmit FCC2 Clock Source is CLK14 */ +#define CMXFCR_TF2CS_CLK15 0x00060000 /* Transmit FCC2 Clock Source is CLK15 */ +#define CMXFCR_TF2CS_CLK16 0x00070000 /* Transmit FCC2 Clock Source is CLK16 */ + +#define CMXFCR_RF3CS_BRG5 0x00000000 /* Receive FCC3 Clock Source is BRG5 */ +#define CMXFCR_RF3CS_BRG6 0x00000800 /* Receive FCC3 Clock Source is BRG6 */ +#define CMXFCR_RF3CS_BRG7 0x00001000 /* Receive FCC3 Clock Source is BRG7 */ +#define CMXFCR_RF3CS_BRG8 0x00001800 /* Receive FCC3 Clock Source is BRG8 */ +#define CMXFCR_RF3CS_CLK13 0x00002000 /* Receive FCC3 Clock Source is CLK13 */ +#define CMXFCR_RF3CS_CLK14 0x00002800 /* Receive FCC3 Clock Source is CLK14 */ +#define CMXFCR_RF3CS_CLK15 0x00003000 /* Receive FCC3 Clock Source is CLK15 */ +#define CMXFCR_RF3CS_CLK16 0x00003800 /* Receive FCC3 Clock Source is CLK16 */ + +#define CMXFCR_TF3CS_BRG5 0x00000000 /* Transmit FCC3 Clock Source is BRG5 */ +#define CMXFCR_TF3CS_BRG6 0x00000100 /* Transmit FCC3 Clock Source is BRG6 */ +#define CMXFCR_TF3CS_BRG7 0x00000200 /* Transmit FCC3 Clock Source is BRG7 */ +#define CMXFCR_TF3CS_BRG8 0x00000300 /* Transmit FCC3 Clock Source is BRG8 */ +#define CMXFCR_TF3CS_CLK13 0x00000400 /* Transmit FCC3 Clock Source is CLK13 */ +#define CMXFCR_TF3CS_CLK14 0x00000500 /* Transmit FCC3 Clock Source is CLK14 */ +#define CMXFCR_TF3CS_CLK15 0x00000600 /* Transmit FCC3 Clock Source is CLK15 */ +#define CMXFCR_TF3CS_CLK16 0x00000700 /* Transmit FCC3 Clock Source is CLK16 */ + +/*----------------------------------------------------------------------- + * CMXSCR - CMX SCC Clock Route Register + */ +#define CMXSCR_GR1 0x80000000 /* Grant Support of SCC1 */ +#define CMXSCR_SC1 0x40000000 /* SCC1 connection */ +#define CMXSCR_RS1CS_MSK 0x38000000 /* Receive SCC1 Clock Source Mask */ +#define CMXSCR_TS1CS_MSK 0x07000000 /* Transmit SCC1 Clock Source Mask */ +#define CMXSCR_GR2 0x00800000 /* Grant Support of SCC2 */ +#define CMXSCR_SC2 0x00400000 /* SCC2 connection */ +#define CMXSCR_RS2CS_MSK 0x00380000 /* Receive SCC2 Clock Source Mask */ +#define CMXSCR_TS2CS_MSK 0x00070000 /* Transmit SCC2 Clock Source Mask */ +#define CMXSCR_GR3 0x00008000 /* Grant Support of SCC3 */ +#define CMXSCR_SC3 0x00004000 /* SCC3 connection */ +#define CMXSCR_RS3CS_MSK 0x00003800 /* Receive SCC3 Clock Source Mask */ +#define CMXSCR_TS3CS_MSK 0x00000700 /* Transmit SCC3 Clock Source Mask */ +#define CMXSCR_GR4 0x00000080 /* Grant Support of SCC4 */ +#define CMXSCR_SC4 0x00000040 /* SCC4 connection */ +#define CMXSCR_RS4CS_MSK 0x00000038 /* Receive SCC4 Clock Source Mask */ +#define CMXSCR_TS4CS_MSK 0x00000007 /* Transmit SCC4 Clock Source Mask */ + +#define CMXSCR_RS1CS_BRG1 0x00000000 /* SCC1 Rx Clock Source is BRG1 */ +#define CMXSCR_RS1CS_BRG2 0x08000000 /* SCC1 Rx Clock Source is BRG2 */ +#define CMXSCR_RS1CS_BRG3 0x10000000 /* SCC1 Rx Clock Source is BRG3 */ +#define CMXSCR_RS1CS_BRG4 0x18000000 /* SCC1 Rx Clock Source is BRG4 */ +#define CMXSCR_RS1CS_CLK11 0x20000000 /* SCC1 Rx Clock Source is CLK11 */ +#define CMXSCR_RS1CS_CLK12 0x28000000 /* SCC1 Rx Clock Source is CLK12 */ +#define CMXSCR_RS1CS_CLK3 0x30000000 /* SCC1 Rx Clock Source is CLK3 */ +#define CMXSCR_RS1CS_CLK4 0x38000000 /* SCC1 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS1CS_BRG1 0x00000000 /* SCC1 Tx Clock Source is BRG1 */ +#define CMXSCR_TS1CS_BRG2 0x01000000 /* SCC1 Tx Clock Source is BRG2 */ +#define CMXSCR_TS1CS_BRG3 0x02000000 /* SCC1 Tx Clock Source is BRG3 */ +#define CMXSCR_TS1CS_BRG4 0x03000000 /* SCC1 Tx Clock Source is BRG4 */ +#define CMXSCR_TS1CS_CLK11 0x04000000 /* SCC1 Tx Clock Source is CLK11 */ +#define CMXSCR_TS1CS_CLK12 0x05000000 /* SCC1 Tx Clock Source is CLK12 */ +#define CMXSCR_TS1CS_CLK3 0x06000000 /* SCC1 Tx Clock Source is CLK3 */ +#define CMXSCR_TS1CS_CLK4 0x07000000 /* SCC1 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS2CS_BRG1 0x00000000 /* SCC2 Rx Clock Source is BRG1 */ +#define CMXSCR_RS2CS_BRG2 0x00080000 /* SCC2 Rx Clock Source is BRG2 */ +#define CMXSCR_RS2CS_BRG3 0x00100000 /* SCC2 Rx Clock Source is BRG3 */ +#define CMXSCR_RS2CS_BRG4 0x00180000 /* SCC2 Rx Clock Source is BRG4 */ +#define CMXSCR_RS2CS_CLK11 0x00200000 /* SCC2 Rx Clock Source is CLK11 */ +#define CMXSCR_RS2CS_CLK12 0x00280000 /* SCC2 Rx Clock Source is CLK12 */ +#define CMXSCR_RS2CS_CLK3 0x00300000 /* SCC2 Rx Clock Source is CLK3 */ +#define CMXSCR_RS2CS_CLK4 0x00380000 /* SCC2 Rx Clock Source is CLK4 */ + +#define CMXSCR_TS2CS_BRG1 0x00000000 /* SCC2 Tx Clock Source is BRG1 */ +#define CMXSCR_TS2CS_BRG2 0x00010000 /* SCC2 Tx Clock Source is BRG2 */ +#define CMXSCR_TS2CS_BRG3 0x00020000 /* SCC2 Tx Clock Source is BRG3 */ +#define CMXSCR_TS2CS_BRG4 0x00030000 /* SCC2 Tx Clock Source is BRG4 */ +#define CMXSCR_TS2CS_CLK11 0x00040000 /* SCC2 Tx Clock Source is CLK11 */ +#define CMXSCR_TS2CS_CLK12 0x00050000 /* SCC2 Tx Clock Source is CLK12 */ +#define CMXSCR_TS2CS_CLK3 0x00060000 /* SCC2 Tx Clock Source is CLK3 */ +#define CMXSCR_TS2CS_CLK4 0x00070000 /* SCC2 Tx Clock Source is CLK4 */ + +#define CMXSCR_RS3CS_BRG1 0x00000000 /* SCC3 Rx Clock Source is BRG1 */ +#define CMXSCR_RS3CS_BRG2 0x00000800 /* SCC3 Rx Clock Source is BRG2 */ +#define CMXSCR_RS3CS_BRG3 0x00001000 /* SCC3 Rx Clock Source is BRG3 */ +#define CMXSCR_RS3CS_BRG4 0x00001800 /* SCC3 Rx Clock Source is BRG4 */ +#define CMXSCR_RS3CS_CLK5 0x00002000 /* SCC3 Rx Clock Source is CLK5 */ +#define CMXSCR_RS3CS_CLK6 0x00002800 /* SCC3 Rx Clock Source is CLK6 */ +#define CMXSCR_RS3CS_CLK7 0x00003000 /* SCC3 Rx Clock Source is CLK7 */ +#define CMXSCR_RS3CS_CLK8 0x00003800 /* SCC3 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS3CS_BRG1 0x00000000 /* SCC3 Tx Clock Source is BRG1 */ +#define CMXSCR_TS3CS_BRG2 0x00000100 /* SCC3 Tx Clock Source is BRG2 */ +#define CMXSCR_TS3CS_BRG3 0x00000200 /* SCC3 Tx Clock Source is BRG3 */ +#define CMXSCR_TS3CS_BRG4 0x00000300 /* SCC3 Tx Clock Source is BRG4 */ +#define CMXSCR_TS3CS_CLK5 0x00000400 /* SCC3 Tx Clock Source is CLK5 */ +#define CMXSCR_TS3CS_CLK6 0x00000500 /* SCC3 Tx Clock Source is CLK6 */ +#define CMXSCR_TS3CS_CLK7 0x00000600 /* SCC3 Tx Clock Source is CLK7 */ +#define CMXSCR_TS3CS_CLK8 0x00000700 /* SCC3 Tx Clock Source is CLK8 */ + +#define CMXSCR_RS4CS_BRG1 0x00000000 /* SCC4 Rx Clock Source is BRG1 */ +#define CMXSCR_RS4CS_BRG2 0x00000008 /* SCC4 Rx Clock Source is BRG2 */ +#define CMXSCR_RS4CS_BRG3 0x00000010 /* SCC4 Rx Clock Source is BRG3 */ +#define CMXSCR_RS4CS_BRG4 0x00000018 /* SCC4 Rx Clock Source is BRG4 */ +#define CMXSCR_RS4CS_CLK5 0x00000020 /* SCC4 Rx Clock Source is CLK5 */ +#define CMXSCR_RS4CS_CLK6 0x00000028 /* SCC4 Rx Clock Source is CLK6 */ +#define CMXSCR_RS4CS_CLK7 0x00000030 /* SCC4 Rx Clock Source is CLK7 */ +#define CMXSCR_RS4CS_CLK8 0x00000038 /* SCC4 Rx Clock Source is CLK8 */ + +#define CMXSCR_TS4CS_BRG1 0x00000000 /* SCC4 Tx Clock Source is BRG1 */ +#define CMXSCR_TS4CS_BRG2 0x00000001 /* SCC4 Tx Clock Source is BRG2 */ +#define CMXSCR_TS4CS_BRG3 0x00000002 /* SCC4 Tx Clock Source is BRG3 */ +#define CMXSCR_TS4CS_BRG4 0x00000003 /* SCC4 Tx Clock Source is BRG4 */ +#define CMXSCR_TS4CS_CLK5 0x00000004 /* SCC4 Tx Clock Source is CLK5 */ +#define CMXSCR_TS4CS_CLK6 0x00000005 /* SCC4 Tx Clock Source is CLK6 */ +#define CMXSCR_TS4CS_CLK7 0x00000006 /* SCC4 Tx Clock Source is CLK7 */ +#define CMXSCR_TS4CS_CLK8 0x00000007 /* SCC4 Tx Clock Source is CLK8 */ + +#endif /* __CPM2__ */ +#endif /* __KERNEL__ */ + + diff -urN linux-2.4.25/include/asm-ppc/cpm_8260.h linux-2.4.26/include/asm-ppc/cpm_8260.h --- linux-2.4.25/include/asm-ppc/cpm_8260.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/cpm_8260.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,702 +0,0 @@ -/* - * MPC8260 Communication Processor Module. - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) - * - * This file contains structures and information for the communication - * processor channels found in the dual port RAM or parameter RAM. - * All CPM control and status is available through the MPC8260 internal - * memory map. See immap.h for details. - */ -#ifdef __KERNEL__ -#ifndef __CPM_82XX__ -#define __CPM_82XX__ - -#include - -/* CPM Command register. -*/ -#define CPM_CR_RST ((uint)0x80000000) -#define CPM_CR_PAGE ((uint)0x7c000000) -#define CPM_CR_SBLOCK ((uint)0x03e00000) -#define CPM_CR_FLG ((uint)0x00010000) -#define CPM_CR_MCN ((uint)0x00003fc0) -#define CPM_CR_OPCODE ((uint)0x0000000f) - -/* Device sub-block and page codes. -*/ -#define CPM_CR_SCC1_SBLOCK (0x04) -#define CPM_CR_SCC2_SBLOCK (0x05) -#define CPM_CR_SCC3_SBLOCK (0x06) -#define CPM_CR_SCC4_SBLOCK (0x07) -#define CPM_CR_SMC1_SBLOCK (0x08) -#define CPM_CR_SMC2_SBLOCK (0x09) -#define CPM_CR_SPI_SBLOCK (0x0a) -#define CPM_CR_I2C_SBLOCK (0x0b) -#define CPM_CR_TIMER_SBLOCK (0x0f) -#define CPM_CR_RAND_SBLOCK (0x0e) -#define CPM_CR_FCC1_SBLOCK (0x10) -#define CPM_CR_FCC2_SBLOCK (0x11) -#define CPM_CR_FCC3_SBLOCK (0x12) -#define CPM_CR_IDMA1_SBLOCK (0x14) -#define CPM_CR_IDMA2_SBLOCK (0x15) -#define CPM_CR_IDMA3_SBLOCK (0x16) -#define CPM_CR_IDMA4_SBLOCK (0x17) -#define CPM_CR_MCC1_SBLOCK (0x1c) - -#define CPM_CR_SCC1_PAGE (0x00) -#define CPM_CR_SCC2_PAGE (0x01) -#define CPM_CR_SCC3_PAGE (0x02) -#define CPM_CR_SCC4_PAGE (0x03) -#define CPM_CR_SMC1_PAGE (0x07) -#define CPM_CR_SMC2_PAGE (0x08) -#define CPM_CR_SPI_PAGE (0x09) -#define CPM_CR_I2C_PAGE (0x0a) -#define CPM_CR_TIMER_PAGE (0x0a) -#define CPM_CR_RAND_PAGE (0x0a) -#define CPM_CR_FCC1_PAGE (0x04) -#define CPM_CR_FCC2_PAGE (0x05) -#define CPM_CR_FCC3_PAGE (0x06) -#define CPM_CR_IDMA1_PAGE (0x07) -#define CPM_CR_IDMA2_PAGE (0x08) -#define CPM_CR_IDMA3_PAGE (0x09) -#define CPM_CR_IDMA4_PAGE (0x0a) -#define CPM_CR_MCC1_PAGE (0x07) -#define CPM_CR_MCC2_PAGE (0x08) - -/* Some opcodes (there are more...later) -*/ -#define CPM_CR_INIT_TRX ((ushort)0x0000) -#define CPM_CR_INIT_RX ((ushort)0x0001) -#define CPM_CR_INIT_TX ((ushort)0x0002) -#define CPM_CR_HUNT_MODE ((ushort)0x0003) -#define CPM_CR_STOP_TX ((ushort)0x0004) -#define CPM_CR_RESTART_TX ((ushort)0x0006) -#define CPM_CR_SET_GADDR ((ushort)0x0008) - -#define mk_cr_cmd(PG, SBC, MCN, OP) \ - ((PG << 26) | (SBC << 21) | (MCN << 6) | OP) - -/* Dual Port RAM addresses. The first 16K is available for almost - * any CPM use, so we put the BDs there. The first 128 bytes are - * used for SMC1 and SMC2 parameter RAM, so we start allocating - * BDs above that. All of this must change when we start - * downloading RAM microcode. - */ -#define CPM_DATAONLY_BASE ((uint)128) -#define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) -#define CPM_DP_NOSPACE ((uint)0x7fffffff) -#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) - -/* The number of pages of host memory we allocate for CPM. This is - * done early in kernel initialization to get physically contiguous - * pages. - */ -#define NUM_CPM_HOST_PAGES 2 - - -/* Export the base address of the communication processor registers - * and dual port ram. - */ -extern cpm8260_t *cpmp; /* Pointer to comm processor */ -uint m8260_cpm_dpalloc(uint size, uint align); -uint m8260_cpm_hostalloc(uint size, uint align); -void m8260_cpm_setbrg(uint brg, uint rate); -void m8260_cpm_fastbrg(uint brg, uint rate, int div16); - -/* Buffer descriptors used by many of the CPM protocols. -*/ -typedef struct cpm_buf_desc { - ushort cbd_sc; /* Status and Control */ - ushort cbd_datlen; /* Data length in buffer */ - uint cbd_bufaddr; /* Buffer address in host memory */ -} cbd_t; - -#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ -#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ -#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ -#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ -#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame */ -#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ -#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ -#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ -#define BD_SC_BR ((ushort)0x0020) /* Break received */ -#define BD_SC_FR ((ushort)0x0010) /* Framing error */ -#define BD_SC_PR ((ushort)0x0008) /* Parity error */ -#define BD_SC_OV ((ushort)0x0002) /* Overrun */ -#define BD_SC_CD ((ushort)0x0001) /* ?? */ - -/* Function code bits, usually generic to devices. -*/ -#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ -#define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ -#define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ -#define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ -#define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ - -/* Parameter RAM offsets from the base. -*/ -#define PROFF_SCC1 ((uint)0x8000) -#define PROFF_SCC2 ((uint)0x8100) -#define PROFF_SCC3 ((uint)0x8200) -#define PROFF_SCC4 ((uint)0x8300) -#define PROFF_FCC1 ((uint)0x8400) -#define PROFF_FCC2 ((uint)0x8500) -#define PROFF_FCC3 ((uint)0x8600) -#define PROFF_MCC1 ((uint)0x8700) -#define PROFF_SMC1_BASE ((uint)0x87fc) -#define PROFF_IDMA1_BASE ((uint)0x87fe) -#define PROFF_MCC2 ((uint)0x8800) -#define PROFF_SMC2_BASE ((uint)0x88fc) -#define PROFF_IDMA2_BASE ((uint)0x88fe) -#define PROFF_SPI_BASE ((uint)0x89fc) -#define PROFF_IDMA3_BASE ((uint)0x89fe) -#define PROFF_TIMERS ((uint)0x8ae0) -#define PROFF_REVNUM ((uint)0x8af0) -#define PROFF_RAND ((uint)0x8af8) -#define PROFF_I2C_BASE ((uint)0x8afc) -#define PROFF_IDMA4_BASE ((uint)0x8afe) - -/* The SMCs are relocated to any of the first eight DPRAM pages. - * We will fix these at the first locations of DPRAM, until we - * get some microcode patches :-). - * The parameter ram space for the SMCs is fifty-some bytes, and - * they are required to start on a 64 byte boundary. - */ -#define PROFF_SMC1 (0) -#define PROFF_SMC2 (64) - - -/* Define enough so I can at least use the serial port as a UART. - */ -typedef struct smc_uart { - ushort smc_rbase; /* Rx Buffer descriptor base address */ - ushort smc_tbase; /* Tx Buffer descriptor base address */ - u_char smc_rfcr; /* Rx function code */ - u_char smc_tfcr; /* Tx function code */ - ushort smc_mrblr; /* Max receive buffer length */ - uint smc_rstate; /* Internal */ - uint smc_idp; /* Internal */ - ushort smc_rbptr; /* Internal */ - ushort smc_ibc; /* Internal */ - uint smc_rxtmp; /* Internal */ - uint smc_tstate; /* Internal */ - uint smc_tdp; /* Internal */ - ushort smc_tbptr; /* Internal */ - ushort smc_tbc; /* Internal */ - uint smc_txtmp; /* Internal */ - ushort smc_maxidl; /* Maximum idle characters */ - ushort smc_tmpidl; /* Temporary idle counter */ - ushort smc_brklen; /* Last received break length */ - ushort smc_brkec; /* rcv'd break condition counter */ - ushort smc_brkcr; /* xmt break count register */ - ushort smc_rmask; /* Temporary bit mask */ - uint smc_stmp; /* SDMA Temp */ -} smc_uart_t; - -/* SMC uart mode register (Internal memory map). -*/ -#define SMCMR_REN ((ushort)0x0001) -#define SMCMR_TEN ((ushort)0x0002) -#define SMCMR_DM ((ushort)0x000c) -#define SMCMR_SM_GCI ((ushort)0x0000) -#define SMCMR_SM_UART ((ushort)0x0020) -#define SMCMR_SM_TRANS ((ushort)0x0030) -#define SMCMR_SM_MASK ((ushort)0x0030) -#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ -#define SMCMR_REVD SMCMR_PM_EVEN -#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ -#define SMCMR_BS SMCMR_PEN -#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ -#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ -#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) - -/* SMC Event and Mask register. -*/ -#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ -#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ -#define SMCM_TXE ((unsigned char)0x10) -#define SMCM_BSY ((unsigned char)0x04) -#define SMCM_TX ((unsigned char)0x02) -#define SMCM_RX ((unsigned char)0x01) - -/* Baud rate generators. -*/ -#define CPM_BRG_RST ((uint)0x00020000) -#define CPM_BRG_EN ((uint)0x00010000) -#define CPM_BRG_EXTC_INT ((uint)0x00000000) -#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) -#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) -#define CPM_BRG_ATB ((uint)0x00002000) -#define CPM_BRG_CD_MASK ((uint)0x00001ffe) -#define CPM_BRG_DIV16 ((uint)0x00000001) - -/* SCCs. -*/ -#define SCC_GSMRH_IRP ((uint)0x00040000) -#define SCC_GSMRH_GDE ((uint)0x00010000) -#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) -#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) -#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) -#define SCC_GSMRH_REVD ((uint)0x00002000) -#define SCC_GSMRH_TRX ((uint)0x00001000) -#define SCC_GSMRH_TTX ((uint)0x00000800) -#define SCC_GSMRH_CDP ((uint)0x00000400) -#define SCC_GSMRH_CTSP ((uint)0x00000200) -#define SCC_GSMRH_CDS ((uint)0x00000100) -#define SCC_GSMRH_CTSS ((uint)0x00000080) -#define SCC_GSMRH_TFL ((uint)0x00000040) -#define SCC_GSMRH_RFW ((uint)0x00000020) -#define SCC_GSMRH_TXSY ((uint)0x00000010) -#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) -#define SCC_GSMRH_SYNL8 ((uint)0x00000008) -#define SCC_GSMRH_SYNL4 ((uint)0x00000004) -#define SCC_GSMRH_RTSM ((uint)0x00000002) -#define SCC_GSMRH_RSYN ((uint)0x00000001) - -#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ -#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) -#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) -#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) -#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) -#define SCC_GSMRL_TCI ((uint)0x10000000) -#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) -#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) -#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) -#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) -#define SCC_GSMRL_RINV ((uint)0x02000000) -#define SCC_GSMRL_TINV ((uint)0x01000000) -#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) -#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) -#define SCC_GSMRL_TPL_48 ((uint)0x00800000) -#define SCC_GSMRL_TPL_32 ((uint)0x00600000) -#define SCC_GSMRL_TPL_16 ((uint)0x00400000) -#define SCC_GSMRL_TPL_8 ((uint)0x00200000) -#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) -#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) -#define SCC_GSMRL_TPP_01 ((uint)0x00100000) -#define SCC_GSMRL_TPP_10 ((uint)0x00080000) -#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) -#define SCC_GSMRL_TEND ((uint)0x00040000) -#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) -#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) -#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) -#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) -#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) -#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) -#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) -#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) -#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) -#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) -#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) -#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) -#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) -#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) -#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) -#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) -#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) -#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) -#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ -#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) -#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) -#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) -#define SCC_GSMRL_ENR ((uint)0x00000020) -#define SCC_GSMRL_ENT ((uint)0x00000010) -#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) -#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) -#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) -#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) -#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) -#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) -#define SCC_GSMRL_MODE_UART ((uint)0x00000004) -#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) -#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) -#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) - -#define SCC_TODR_TOD ((ushort)0x8000) - -/* SCC Event and Mask register. -*/ -#define SCCM_TXE ((unsigned char)0x10) -#define SCCM_BSY ((unsigned char)0x04) -#define SCCM_TX ((unsigned char)0x02) -#define SCCM_RX ((unsigned char)0x01) - -typedef struct scc_param { - ushort scc_rbase; /* Rx Buffer descriptor base address */ - ushort scc_tbase; /* Tx Buffer descriptor base address */ - u_char scc_rfcr; /* Rx function code */ - u_char scc_tfcr; /* Tx function code */ - ushort scc_mrblr; /* Max receive buffer length */ - uint scc_rstate; /* Internal */ - uint scc_idp; /* Internal */ - ushort scc_rbptr; /* Internal */ - ushort scc_ibc; /* Internal */ - uint scc_rxtmp; /* Internal */ - uint scc_tstate; /* Internal */ - uint scc_tdp; /* Internal */ - ushort scc_tbptr; /* Internal */ - ushort scc_tbc; /* Internal */ - uint scc_txtmp; /* Internal */ - uint scc_rcrc; /* Internal */ - uint scc_tcrc; /* Internal */ -} sccp_t; - -/* CPM Ethernet through SCC1. - */ -typedef struct scc_enet { - sccp_t sen_genscc; - uint sen_cpres; /* Preset CRC */ - uint sen_cmask; /* Constant mask for CRC */ - uint sen_crcec; /* CRC Error counter */ - uint sen_alec; /* alignment error counter */ - uint sen_disfc; /* discard frame counter */ - ushort sen_pads; /* Tx short frame pad character */ - ushort sen_retlim; /* Retry limit threshold */ - ushort sen_retcnt; /* Retry limit counter */ - ushort sen_maxflr; /* maximum frame length register */ - ushort sen_minflr; /* minimum frame length register */ - ushort sen_maxd1; /* maximum DMA1 length */ - ushort sen_maxd2; /* maximum DMA2 length */ - ushort sen_maxd; /* Rx max DMA */ - ushort sen_dmacnt; /* Rx DMA counter */ - ushort sen_maxb; /* Max BD byte count */ - ushort sen_gaddr1; /* Group address filter */ - ushort sen_gaddr2; - ushort sen_gaddr3; - ushort sen_gaddr4; - uint sen_tbuf0data0; /* Save area 0 - current frame */ - uint sen_tbuf0data1; /* Save area 1 - current frame */ - uint sen_tbuf0rba; /* Internal */ - uint sen_tbuf0crc; /* Internal */ - ushort sen_tbuf0bcnt; /* Internal */ - ushort sen_paddrh; /* physical address (MSB) */ - ushort sen_paddrm; - ushort sen_paddrl; /* physical address (LSB) */ - ushort sen_pper; /* persistence */ - ushort sen_rfbdptr; /* Rx first BD pointer */ - ushort sen_tfbdptr; /* Tx first BD pointer */ - ushort sen_tlbdptr; /* Tx last BD pointer */ - uint sen_tbuf1data0; /* Save area 0 - current frame */ - uint sen_tbuf1data1; /* Save area 1 - current frame */ - uint sen_tbuf1rba; /* Internal */ - uint sen_tbuf1crc; /* Internal */ - ushort sen_tbuf1bcnt; /* Internal */ - ushort sen_txlen; /* Tx Frame length counter */ - ushort sen_iaddr1; /* Individual address filter */ - ushort sen_iaddr2; - ushort sen_iaddr3; - ushort sen_iaddr4; - ushort sen_boffcnt; /* Backoff counter */ - - /* NOTE: Some versions of the manual have the following items - * incorrectly documented. Below is the proper order. - */ - ushort sen_taddrh; /* temp address (MSB) */ - ushort sen_taddrm; - ushort sen_taddrl; /* temp address (LSB) */ -} scc_enet_t; - - -/* SCC Event register as used by Ethernet. -*/ -#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ -#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ -#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ -#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ -#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ -#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ - -/* SCC Mode Register (PSMR) as used by Ethernet. -*/ -#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ -#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ -#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ -#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ -#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ -#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ -#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ -#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ -#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ -#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ -#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ -#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ -#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ - -/* Buffer descriptor control/status used by Ethernet receive. - * Common to SCC and FCC. - */ -#define BD_ENET_RX_EMPTY ((ushort)0x8000) -#define BD_ENET_RX_WRAP ((ushort)0x2000) -#define BD_ENET_RX_INTR ((ushort)0x1000) -#define BD_ENET_RX_LAST ((ushort)0x0800) -#define BD_ENET_RX_FIRST ((ushort)0x0400) -#define BD_ENET_RX_MISS ((ushort)0x0100) -#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ -#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ -#define BD_ENET_RX_LG ((ushort)0x0020) -#define BD_ENET_RX_NO ((ushort)0x0010) -#define BD_ENET_RX_SH ((ushort)0x0008) -#define BD_ENET_RX_CR ((ushort)0x0004) -#define BD_ENET_RX_OV ((ushort)0x0002) -#define BD_ENET_RX_CL ((ushort)0x0001) -#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ - -/* Buffer descriptor control/status used by Ethernet transmit. - * Common to SCC and FCC. - */ -#define BD_ENET_TX_READY ((ushort)0x8000) -#define BD_ENET_TX_PAD ((ushort)0x4000) -#define BD_ENET_TX_WRAP ((ushort)0x2000) -#define BD_ENET_TX_INTR ((ushort)0x1000) -#define BD_ENET_TX_LAST ((ushort)0x0800) -#define BD_ENET_TX_TC ((ushort)0x0400) -#define BD_ENET_TX_DEF ((ushort)0x0200) -#define BD_ENET_TX_HB ((ushort)0x0100) -#define BD_ENET_TX_LC ((ushort)0x0080) -#define BD_ENET_TX_RL ((ushort)0x0040) -#define BD_ENET_TX_RCMASK ((ushort)0x003c) -#define BD_ENET_TX_UN ((ushort)0x0002) -#define BD_ENET_TX_CSL ((ushort)0x0001) -#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ - -/* SCC as UART -*/ -typedef struct scc_uart { - sccp_t scc_genscc; - uint scc_res1; /* Reserved */ - uint scc_res2; /* Reserved */ - ushort scc_maxidl; /* Maximum idle chars */ - ushort scc_idlc; /* temp idle counter */ - ushort scc_brkcr; /* Break count register */ - ushort scc_parec; /* receive parity error counter */ - ushort scc_frmec; /* receive framing error counter */ - ushort scc_nosec; /* receive noise counter */ - ushort scc_brkec; /* receive break condition counter */ - ushort scc_brkln; /* last received break length */ - ushort scc_uaddr1; /* UART address character 1 */ - ushort scc_uaddr2; /* UART address character 2 */ - ushort scc_rtemp; /* Temp storage */ - ushort scc_toseq; /* Transmit out of sequence char */ - ushort scc_char1; /* control character 1 */ - ushort scc_char2; /* control character 2 */ - ushort scc_char3; /* control character 3 */ - ushort scc_char4; /* control character 4 */ - ushort scc_char5; /* control character 5 */ - ushort scc_char6; /* control character 6 */ - ushort scc_char7; /* control character 7 */ - ushort scc_char8; /* control character 8 */ - ushort scc_rccm; /* receive control character mask */ - ushort scc_rccr; /* receive control character register */ - ushort scc_rlbc; /* receive last break character */ -} scc_uart_t; - -/* SCC Event and Mask registers when it is used as a UART. -*/ -#define UART_SCCM_GLR ((ushort)0x1000) -#define UART_SCCM_GLT ((ushort)0x0800) -#define UART_SCCM_AB ((ushort)0x0200) -#define UART_SCCM_IDL ((ushort)0x0100) -#define UART_SCCM_GRA ((ushort)0x0080) -#define UART_SCCM_BRKE ((ushort)0x0040) -#define UART_SCCM_BRKS ((ushort)0x0020) -#define UART_SCCM_CCR ((ushort)0x0008) -#define UART_SCCM_BSY ((ushort)0x0004) -#define UART_SCCM_TX ((ushort)0x0002) -#define UART_SCCM_RX ((ushort)0x0001) - -/* The SCC PMSR when used as a UART. -*/ -#define SCU_PMSR_FLC ((ushort)0x8000) -#define SCU_PMSR_SL ((ushort)0x4000) -#define SCU_PMSR_CL ((ushort)0x3000) -#define SCU_PMSR_UM ((ushort)0x0c00) -#define SCU_PMSR_FRZ ((ushort)0x0200) -#define SCU_PMSR_RZS ((ushort)0x0100) -#define SCU_PMSR_SYN ((ushort)0x0080) -#define SCU_PMSR_DRT ((ushort)0x0040) -#define SCU_PMSR_PEN ((ushort)0x0010) -#define SCU_PMSR_RPM ((ushort)0x000c) -#define SCU_PMSR_REVP ((ushort)0x0008) -#define SCU_PMSR_TPM ((ushort)0x0003) -#define SCU_PMSR_TEVP ((ushort)0x0003) - -/* CPM Transparent mode SCC. - */ -typedef struct scc_trans { - sccp_t st_genscc; - uint st_cpres; /* Preset CRC */ - uint st_cmask; /* Constant mask for CRC */ -} scc_trans_t; - -#define BD_SCC_TX_LAST ((ushort)0x0800) - -/* How about some FCCs..... -*/ -#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) -#define FCC_GFMR_DIAG_LE ((uint)0x40000000) -#define FCC_GFMR_DIAG_AE ((uint)0x80000000) -#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) -#define FCC_GFMR_TCI ((uint)0x20000000) -#define FCC_GFMR_TRX ((uint)0x10000000) -#define FCC_GFMR_TTX ((uint)0x08000000) -#define FCC_GFMR_TTX ((uint)0x08000000) -#define FCC_GFMR_CDP ((uint)0x04000000) -#define FCC_GFMR_CTSP ((uint)0x02000000) -#define FCC_GFMR_CDS ((uint)0x01000000) -#define FCC_GFMR_CTSS ((uint)0x00800000) -#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) -#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) -#define FCC_GFMR_SYNL_8 ((uint)0x00008000) -#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) -#define FCC_GFMR_RTSM ((uint)0x00002000) -#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) -#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) -#define FCC_GFMR_REVD ((uint)0x00000400) -#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) -#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) -#define FCC_GFMR_TCRC_16 ((uint)0x00000000) -#define FCC_GFMR_TCRC_32 ((uint)0x00000080) -#define FCC_GFMR_ENR ((uint)0x00000020) -#define FCC_GFMR_ENT ((uint)0x00000010) -#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) -#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) -#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) - -/* Generic FCC parameter ram. -*/ -typedef struct fcc_param { - ushort fcc_riptr; /* Rx Internal temp pointer */ - ushort fcc_tiptr; /* Tx Internal temp pointer */ - ushort fcc_res1; - ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ - uint fcc_rstate; /* Upper byte is Func code, must be set */ - uint fcc_rbase; /* Receive BD base */ - ushort fcc_rbdstat; /* RxBD status */ - ushort fcc_rbdlen; /* RxBD down counter */ - uint fcc_rdptr; /* RxBD internal data pointer */ - uint fcc_tstate; /* Upper byte is Func code, must be set */ - uint fcc_tbase; /* Transmit BD base */ - ushort fcc_tbdstat; /* TxBD status */ - ushort fcc_tbdlen; /* TxBD down counter */ - uint fcc_tdptr; /* TxBD internal data pointer */ - uint fcc_rbptr; /* Rx BD Internal buf pointer */ - uint fcc_tbptr; /* Tx BD Internal buf pointer */ - uint fcc_rcrc; /* Rx temp CRC */ - uint fcc_res2; - uint fcc_tcrc; /* Tx temp CRC */ -} fccp_t; - - -/* Ethernet controller through FCC. -*/ -typedef struct fcc_enet { - fccp_t fen_genfcc; - uint fen_statbuf; /* Internal status buffer */ - uint fen_camptr; /* CAM address */ - uint fen_cmask; /* Constant mask for CRC */ - uint fen_cpres; /* Preset CRC */ - uint fen_crcec; /* CRC Error counter */ - uint fen_alec; /* alignment error counter */ - uint fen_disfc; /* discard frame counter */ - ushort fen_retlim; /* Retry limit */ - ushort fen_retcnt; /* Retry counter */ - ushort fen_pper; /* Persistence */ - ushort fen_boffcnt; /* backoff counter */ - uint fen_gaddrh; /* Group address filter, high 32-bits */ - uint fen_gaddrl; /* Group address filter, low 32-bits */ - ushort fen_tfcstat; /* out of sequence TxBD */ - ushort fen_tfclen; - uint fen_tfcptr; - ushort fen_mflr; /* Maximum frame length (1518) */ - ushort fen_paddrh; /* MAC address */ - ushort fen_paddrm; - ushort fen_paddrl; - ushort fen_ibdcount; /* Internal BD counter */ - ushort fen_idbstart; /* Internal BD start pointer */ - ushort fen_ibdend; /* Internal BD end pointer */ - ushort fen_txlen; /* Internal Tx frame length counter */ - uint fen_ibdbase[8]; /* Internal use */ - uint fen_iaddrh; /* Individual address filter */ - uint fen_iaddrl; - ushort fen_minflr; /* Minimum frame length (64) */ - ushort fen_taddrh; /* Filter transfer MAC address */ - ushort fen_taddrm; - ushort fen_taddrl; - ushort fen_padptr; /* Pointer to pad byte buffer */ - ushort fen_cftype; /* control frame type */ - ushort fen_cfrange; /* control frame range */ - ushort fen_maxb; /* maximum BD count */ - ushort fen_maxd1; /* Max DMA1 length (1520) */ - ushort fen_maxd2; /* Max DMA2 length (1520) */ - ushort fen_maxd; /* internal max DMA count */ - ushort fen_dmacnt; /* internal DMA counter */ - uint fen_octc; /* Total octect counter */ - uint fen_colc; /* Total collision counter */ - uint fen_broc; /* Total broadcast packet counter */ - uint fen_mulc; /* Total multicast packet count */ - uint fen_uspc; /* Total packets < 64 bytes */ - uint fen_frgc; /* Total packets < 64 bytes with errors */ - uint fen_ospc; /* Total packets > 1518 */ - uint fen_jbrc; /* Total packets > 1518 with errors */ - uint fen_p64c; /* Total packets == 64 bytes */ - uint fen_p65c; /* Total packets 64 < bytes <= 127 */ - uint fen_p128c; /* Total packets 127 < bytes <= 255 */ - uint fen_p256c; /* Total packets 256 < bytes <= 511 */ - uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ - uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ - uint fen_cambuf; /* Internal CAM buffer poiner */ - ushort fen_rfthr; /* Received frames threshold */ - ushort fen_rfcnt; /* Received frames count */ -} fcc_enet_t; - -/* FCC Event/Mask register as used by Ethernet. -*/ -#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ -#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ -#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ -#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ -#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ -#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ -#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ -#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ - -/* FCC Mode Register (FPSMR) as used by Ethernet. -*/ -#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ -#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ -#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ -#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ -#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ -#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ -#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ -#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ -#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ -#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ -#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ -#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ -#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ - -/* IIC parameter RAM. -*/ -typedef struct iic { - ushort iic_rbase; /* Rx Buffer descriptor base address */ - ushort iic_tbase; /* Tx Buffer descriptor base address */ - u_char iic_rfcr; /* Rx function code */ - u_char iic_tfcr; /* Tx function code */ - ushort iic_mrblr; /* Max receive buffer length */ - uint iic_rstate; /* Internal */ - uint iic_rdp; /* Internal */ - ushort iic_rbptr; /* Internal */ - ushort iic_rbc; /* Internal */ - uint iic_rxtmp; /* Internal */ - uint iic_tstate; /* Internal */ - uint iic_tdp; /* Internal */ - ushort iic_tbptr; /* Internal */ - ushort iic_tbc; /* Internal */ - uint iic_txtmp; /* Internal */ -} iic_t; - -#define BD_IIC_START ((ushort)0x0400) - -#endif /* __CPM_82XX__ */ -#endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/asm-ppc/ibm44x.h linux-2.4.26/include/asm-ppc/ibm44x.h --- linux-2.4.25/include/asm-ppc/ibm44x.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/ibm44x.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,9 +4,10 @@ * PPC44x definitions * * Matt Porter - * * Copyright 2002-2003 MontaVista Software Inc. * + * Eugene Surovegin + * * 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 @@ -80,13 +81,34 @@ /* * SPRN definitions */ -#define SPRN_CPC0_GPIO 0xe5/BEARLRL +#define SPRN_CPC0_GPIO 0xe5 /* * DCRN definitions */ #ifdef CONFIG_440GX +/* CPRs */ +#define DCRN_CPR_CONFIG_ADDR 0xc +#define DCRN_CPR_CONFIG_DATA 0xd + +#define DCRN_CPR_CLKUPD 0x0020 +#define DCRN_CPR_PLLC 0x0040 +#define DCRN_CPR_PLLD 0x0060 +#define DCRN_CPR_PRIMAD 0x0080 +#define DCRN_CPR_PRIMBD 0x00a0 +#define DCRN_CPR_OPBD 0x00c0 +#define DCRN_CPR_PERD 0x00e0 +#define DCRN_CPR_MALD 0x0100 + +/* CPRs read/write helper macros */ +#define CPR_READ(offset) ({\ + mtdcr(DCRN_CPR_CONFIG_ADDR, offset); \ + mfdcr(DCRN_CPR_CONFIG_DATA);}) +#define CPR_WRITE(offset, data) ({\ + mtdcr(DCRN_CPR_CONFIG_ADDR, offset); \ + mtdcr(DCRN_CPR_CONFIG_DATA, data);}) + /* SDRs */ #define DCRN_SDR_CONFIG_ADDR 0xe #define DCRN_SDR_CONFIG_DATA 0xf @@ -117,6 +139,8 @@ #define DCRN_SDR_MFR_E3TXFH 0x00000004 #define DCRN_SDR_MFR_E3RXFL 0x00000002 #define DCRN_SDR_MFR_E3RXFH 0x00000001 +#define DCRN_SDR_UART0 0x0120 +#define DCRN_SDR_UART1 0x0121 /* SDR read/write helper macros */ #define SDR_READ(offset) ({\ @@ -327,6 +351,81 @@ #define PPC44x_MEM_SIZE_256M 0x10000000 #define PPC44x_MEM_SIZE_512M 0x20000000 +#ifdef CONFIG_440GX +/* Internal SRAM Controller */ +#define DCRN_SRAM0_SB0CR 0x020 +#define DCRN_SRAM0_SB1CR 0x021 +#define DCRN_SRAM0_SB2CR 0x022 +#define DCRN_SRAM0_SB3CR 0x023 +#define SRAM_SBCR_BAS0 0x80000000 +#define SRAM_SBCR_BAS1 0x80010000 +#define SRAM_SBCR_BAS2 0x80020000 +#define SRAM_SBCR_BAS3 0x80030000 +#define SRAM_SBCR_BU_MASK 0x00000180 +#define SRAM_SBCR_BS_64KB 0x00000800 +#define SRAM_SBCR_BU_RO 0x00000080 +#define SRAM_SBCR_BU_RW 0x00000180 +#define DCRN_SRAM0_BEAR 0x024 +#define DCRN_SRAM0_BESR0 0x025 +#define DCRN_SRAM0_BESR1 0x026 +#define DCRN_SRAM0_PMEG 0x027 +#define DCRN_SRAM0_CID 0x028 +#define DCRN_SRAM0_REVID 0x029 +#define DCRN_SRAM0_DPC 0x02a +#define SRAM_DPC_ENABLE 0x80000000 + +/* L2 Cache Controller */ +#define DCRN_L2C0_CFG 0x030 +#define L2C_CFG_L2M 0x80000000 +#define L2C_CFG_ICU 0x40000000 +#define L2C_CFG_DCU 0x20000000 +#define L2C_CFG_DCW_MASK 0x1e000000 +#define L2C_CFG_TPC 0x01000000 +#define L2C_CFG_CPC 0x00800000 +#define L2C_CFG_FRAN 0x00200000 +#define L2C_CFG_SS_MASK 0x00180000 +#define L2C_CFG_SS_256 0x00000000 +#define L2C_CFG_CPIM 0x00040000 +#define L2C_CFG_TPIM 0x00020000 +#define L2C_CFG_LIM 0x00010000 +#define L2C_CFG_PMUX_MASK 0x00007000 +#define L2C_CFG_PMUX_SNP 0x00000000 +#define L2C_CFG_PMUX_IF 0x00001000 +#define L2C_CFG_PMUX_DF 0x00002000 +#define L2C_CFG_PMUX_DS 0x00003000 +#define L2C_CFG_PMIM 0x00000800 +#define L2C_CFG_TPEI 0x00000400 +#define L2C_CFG_CPEI 0x00000200 +#define L2C_CFG_NAM 0x00000100 +#define L2C_CFG_SMCM 0x00000080 +#define L2C_CFG_NBRM 0x00000040 +#define DCRN_L2C0_CMD 0x031 +#define L2C_CMD_CLR 0x80000000 +#define L2C_CMD_DIAG 0x40000000 +#define L2C_CMD_INV 0x20000000 +#define L2C_CMD_CCP 0x10000000 +#define L2C_CMD_CTE 0x08000000 +#define L2C_CMD_STRC 0x04000000 +#define L2C_CMD_STPC 0x02000000 +#define L2C_CMD_RPMC 0x01000000 +#define L2C_CMD_HCC 0x00800000 +#define DCRN_L2C0_ADDR 0x032 +#define DCRN_L2C0_DATA 0x033 +#define DCRN_L2C0_SR 0x034 +#define L2C_SR_CC 0x80000000 +#define L2C_SR_CPE 0x40000000 +#define L2C_SR_TPE 0x20000000 +#define L2C_SR_LRU 0x10000000 +#define L2C_SR_PCS 0x08000000 +#define DCRN_L2C0_REVID 0x035 +#define DCRN_L2C0_SNP0 0x036 +#define DCRN_L2C0_SNP1 0x037 +#define L2C_SNP_BA_MASK 0xffff0000 +#define L2C_SNP_SSR_MASK 0x0000f000 +#define L2C_SNP_SSR_32G 0x0000f000 +#define L2C_SNP_ESR 0x00000800 +#endif /* CONFIG_440GX */ + /* * PCI-X definitions */ diff -urN linux-2.4.25/include/asm-ppc/ibm4xx.h linux-2.4.26/include/asm-ppc/ibm4xx.h --- linux-2.4.25/include/asm-ppc/ibm4xx.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/ibm4xx.h 2004-04-14 06:05:40.000000000 -0700 @@ -62,10 +62,22 @@ #include #endif +#if defined(CONFIG_EP405) +#include +#endif + #if defined(CONFIG_OAK) #include #endif +#if defined(CONFIG_REDWOOD_5) +#include +#endif + +#if defined(CONFIG_REDWOOD_6) +#include +#endif + #if defined(CONFIG_WALNUT) #include #endif diff -urN linux-2.4.25/include/asm-ppc/immap_8260.h linux-2.4.26/include/asm-ppc/immap_8260.h --- linux-2.4.25/include/asm-ppc/immap_8260.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-ppc/immap_8260.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,433 +0,0 @@ -/* - * MPC8260 Internal Memory Map - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) - * - * The Internal Memory Map of the 8260. I don't know how generic - * this will be, as I don't have any knowledge of the subsequent - * parts at this time. I copied this from the 8xx_immap.h. - */ -#ifdef __KERNEL__ -#ifndef __IMMAP_82XX__ -#define __IMMAP_82XX__ - -/* System configuration registers. -*/ -typedef struct sys_conf { - uint sc_siumcr; - uint sc_sypcr; - char res1[6]; - ushort sc_swsr; - char res2[20]; - uint sc_bcr; - u_char sc_ppc_acr; - char res3[3]; - uint sc_ppc_alrh; - uint sc_ppc_alrl; - u_char sc_lcl_acr; - char res4[3]; - uint sc_lcl_alrh; - uint sc_lcl_alrl; - uint sc_tescr1; - uint sc_tescr2; - uint sc_ltescr1; - uint sc_ltescr2; - uint sc_pdtea; - u_char sc_pdtem; - char res5[3]; - uint sc_ldtea; - u_char sc_ldtem; - char res6[163]; -} sysconf8260_t; - - -/* Memory controller registers. -*/ -typedef struct mem_ctlr { - uint memc_br0; - uint memc_or0; - uint memc_br1; - uint memc_or1; - uint memc_br2; - uint memc_or2; - uint memc_br3; - uint memc_or3; - uint memc_br4; - uint memc_or4; - uint memc_br5; - uint memc_or5; - uint memc_br6; - uint memc_or6; - uint memc_br7; - uint memc_or7; - uint memc_br8; - uint memc_or8; - uint memc_br9; - uint memc_or9; - uint memc_br10; - uint memc_or10; - uint memc_br11; - uint memc_or11; - char res1[8]; - uint memc_mar; - char res2[4]; - uint memc_mamr; - uint memc_mbmr; - uint memc_mcmr; - char res3[8]; - ushort memc_mptpr; - char res4[2]; - uint memc_mdr; - char res5[4]; - uint memc_psdmr; - uint memc_lsdmr; - u_char memc_purt; - char res6[3]; - u_char memc_psrt; - char res7[3]; - u_char memc_lurt; - char res8[3]; - u_char memc_lsrt; - char res9[3]; - uint memc_immr; - char res10[84]; -} memctl8260_t; - -/* System Integration Timers. -*/ -typedef struct sys_int_timers { - char res1[32]; - ushort sit_tmcntsc; - char res2[2]; - uint sit_tmcnt; - char res3[4]; - uint sit_tmcntal; - char res4[16]; - ushort sit_piscr; - char res5[2]; - uint sit_pitc; - uint sit_pitr; - char res6[94]; - char res7[2390]; -} sit8260_t; - -#define PISCR_PIRQ_MASK ((ushort)0xff00) -#define PISCR_PS ((ushort)0x0080) -#define PISCR_PIE ((ushort)0x0004) -#define PISCR_PTF ((ushort)0x0002) -#define PISCR_PTE ((ushort)0x0001) - -/* Interrupt Controller. -*/ -typedef struct interrupt_controller { - ushort ic_sicr; - char res1[2]; - uint ic_sivec; - uint ic_sipnrh; - uint ic_sipnrl; - uint ic_siprr; - uint ic_scprrh; - uint ic_scprrl; - uint ic_simrh; - uint ic_simrl; - uint ic_siexr; - char res2[88]; -} intctl8260_t; - -/* Clocks and Reset. -*/ -typedef struct clk_and_reset { - uint car_sccr; - char res1[4]; - uint car_scmr; - char res2[4]; - uint car_rsr; - uint car_rmr; - char res[104]; -} car8260_t; - -/* Input/Output Port control/status registers. - * Names consistent with processor manual, although they are different - * from the original 8xx names....... - */ -typedef struct io_port { - uint iop_pdira; - uint iop_ppara; - uint iop_psora; - uint iop_podra; - uint iop_pdata; - char res1[12]; - uint iop_pdirb; - uint iop_pparb; - uint iop_psorb; - uint iop_podrb; - uint iop_pdatb; - char res2[12]; - uint iop_pdirc; - uint iop_pparc; - uint iop_psorc; - uint iop_podrc; - uint iop_pdatc; - char res3[12]; - uint iop_pdird; - uint iop_ppard; - uint iop_psord; - uint iop_podrd; - uint iop_pdatd; - char res4[12]; -} iop8260_t; - -/* Communication Processor Module Timers -*/ -typedef struct cpm_timers { - u_char cpmt_tgcr1; - char res1[3]; - u_char cpmt_tgcr2; - char res2[11]; - ushort cpmt_tmr1; - ushort cpmt_tmr2; - ushort cpmt_trr1; - ushort cpmt_trr2; - ushort cpmt_tcr1; - ushort cpmt_tcr2; - ushort cpmt_tcn1; - ushort cpmt_tcn2; - ushort cpmt_tmr3; - ushort cpmt_tmr4; - ushort cpmt_trr3; - ushort cpmt_trr4; - ushort cpmt_tcr3; - ushort cpmt_tcr4; - ushort cpmt_tcn3; - ushort cpmt_tcn4; - ushort cpmt_ter1; - ushort cpmt_ter2; - ushort cpmt_ter3; - ushort cpmt_ter4; - char res3[584]; -} cpmtimer8260_t; - -/* DMA control/status registers. -*/ -typedef struct sdma_csr { - char res0[24]; - u_char sdma_sdsr; - char res1[3]; - u_char sdma_sdmr; - char res2[3]; - u_char sdma_idsr1; - char res3[3]; - u_char sdma_idmr1; - char res4[3]; - u_char sdma_idsr2; - char res5[3]; - u_char sdma_idmr2; - char res6[3]; - u_char sdma_idsr3; - char res7[3]; - u_char sdma_idmr3; - char res8[3]; - u_char sdma_idsr4; - char res9[3]; - u_char sdma_idmr4; - char res10[707]; -} sdma8260_t; - -/* Fast controllers -*/ -typedef struct fcc { - uint fcc_gfmr; - uint fcc_fpsmr; - ushort fcc_ftodr; - char res1[2]; - ushort fcc_fdsr; - char res2[2]; - ushort fcc_fcce; - char res3[2]; - ushort fcc_fccm; - char res4[2]; - u_char fcc_fccs; - char res5[3]; - u_char fcc_ftirr_phy[4]; -} fcc_t; - -/* I2C -*/ -typedef struct i2c { - u_char i2c_i2mod; - char res1[3]; - u_char i2c_i2add; - char res2[3]; - u_char i2c_i2brg; - char res3[3]; - u_char i2c_i2com; - char res4[3]; - u_char i2c_i2cer; - char res5[3]; - u_char i2c_i2cmr; - char res6[331]; -} i2c8260_t; - -typedef struct scc { /* Serial communication channels */ - uint scc_gsmrl; - uint scc_gsmrh; - ushort scc_pmsr; - char res1[2]; - ushort scc_todr; - ushort scc_dsr; - ushort scc_scce; - char res2[2]; - ushort scc_sccm; - char res3; - u_char scc_sccs; - char res4[8]; -} scc_t; - -typedef struct smc { /* Serial management channels */ - char res1[2]; - ushort smc_smcmr; - char res2[2]; - u_char smc_smce; - char res3[3]; - u_char smc_smcm; - char res4[5]; -} smc_t; - -/* Serial Peripheral Interface. -*/ -typedef struct spi { - ushort spi_spmode; - char res1[4]; - u_char spi_spie; - char res2[3]; - u_char spi_spim; - char res3[2]; - u_char spi_spcom; - char res4[82]; -} spi_t; - -/* CPM Mux. -*/ -typedef struct cpmux { - u_char cmx_si1cr; - char res1; - u_char cmx_si2cr; - char res2; - uint cmx_fcr; - uint cmx_scr; - u_char cmx_smr; - char res3; - ushort cmx_uar; - char res4[16]; -} cpmux_t; - -/* SIRAM control -*/ -typedef struct siram { - ushort si_amr; - ushort si_bmr; - ushort si_cmr; - ushort si_dmr; - u_char si_gmr; - char res1; - u_char si_cmdr; - char res2; - u_char si_str; - char res3; - ushort si_rsr; -} siramctl_t; - -typedef struct mcc { - ushort mcc_mcce; - char res1[2]; - ushort mcc_mccm; - char res2[2]; - u_char mcc_mccf; - char res3[7]; -} mcc_t; - -typedef struct comm_proc { - uint cp_cpcr; - uint cp_rccr; - char res1[14]; - ushort cp_rter; - char res2[2]; - ushort cp_rtmr; - ushort cp_rtscr; - char res3[2]; - uint cp_rtsr; - char res4[12]; -} cpm8260_t; - -/* ...and the whole thing wrapped up.... -*/ -typedef struct immap { - /* Some references are into the unique and known dpram spaces, - * others are from the generic base. - */ -#define im_dprambase im_dpram1 - u_char im_dpram1[16*1024]; - char res1[16*1024]; - u_char im_dpram2[4*1024]; - char res2[8*1024]; - u_char im_dpram3[4*1024]; - char res3[16*1024]; - - sysconf8260_t im_siu_conf; /* SIU Configuration */ - memctl8260_t im_memctl; /* Memory Controller */ - sit8260_t im_sit; /* System Integration Timers */ - intctl8260_t im_intctl; /* Interrupt Controller */ - car8260_t im_clkrst; /* Clocks and reset */ - iop8260_t im_ioport; /* IO Port control/status */ - cpmtimer8260_t im_cpmtimer; /* CPM timers */ - sdma8260_t im_sdma; /* SDMA control/status */ - - fcc_t im_fcc[3]; /* Three FCCs */ - - char res4[159]; - - /* First set of baud rate generators. - */ - char res4a[496]; - uint im_brgc5; - uint im_brgc6; - uint im_brgc7; - uint im_brgc8; - - char res5[608]; - - i2c8260_t im_i2c; /* I2C control/status */ - cpm8260_t im_cpm; /* Communication processor */ - - /* Second set of baud rate generators. - */ - uint im_brgc1; - uint im_brgc2; - uint im_brgc3; - uint im_brgc4; - - scc_t im_scc[4]; /* Four SCCs */ - smc_t im_smc[2]; /* Couple of SMCs */ - spi_t im_spi; /* A SPI */ - cpmux_t im_cpmux; /* CPM clock route mux */ - siramctl_t im_siramctl1; /* First SI RAM Control */ - mcc_t im_mcc1; /* First MCC */ - siramctl_t im_siramctl2; /* Second SI RAM Control */ - mcc_t im_mcc2; /* Second MCC */ - - char res6[1184]; - - ushort im_si1txram[256]; - char res7[512]; - ushort im_si1rxram[256]; - char res8[512]; - ushort im_si2txram[256]; - char res9[512]; - ushort im_si2rxram[256]; - char res10[512]; - char res11[4096]; -} immap_t; - -extern immap_t *immr; - -#endif /* __IMMAP_82XX__ */ -#endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/asm-ppc/immap_cpm2.h linux-2.4.26/include/asm-ppc/immap_cpm2.h --- linux-2.4.25/include/asm-ppc/immap_cpm2.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/immap_cpm2.h 2004-04-14 06:05:40.000000000 -0700 @@ -0,0 +1,648 @@ +/* + * CPM2 Internal Memory Map + * Copyright (c) 1999 Dan Malek (dmalek@jlc.net) + * + * The Internal Memory Map for devices with CPM2 on them. This + * is the superset of all CPM2 devices (8260, 8266, 8280, 8272, + * 8560). + */ +#ifdef __KERNEL__ +#ifndef __IMMAP_CPM2__ +#define __IMMAP_CPM2__ + +/* System configuration registers. +*/ +typedef struct sys_82xx_conf { + u32 sc_siumcr; + u32 sc_sypcr; + u8 res1[6]; + u16 sc_swsr; + u8 res2[20]; + u32 sc_bcr; + u8 sc_ppc_acr; + u8 res3[3]; + u32 sc_ppc_alrh; + u32 sc_ppc_alrl; + u8 sc_lcl_acr; + u8 res4[3]; + u32 sc_lcl_alrh; + u32 sc_lcl_alrl; + u32 sc_tescr1; + u32 sc_tescr2; + u32 sc_ltescr1; + u32 sc_ltescr2; + u32 sc_pdtea; + u8 sc_pdtem; + u8 res5[3]; + u32 sc_ldtea; + u8 sc_ldtem; + u8 res6[163]; +} sysconf_82xx_cpm2_t; + +typedef struct sys_85xx_conf { + u32 sc_cear; + u16 sc_ceer; + u16 sc_cemr; + u8 res1[70]; + u32 sc_smaer; + u8 res2[4]; + u32 sc_smevr; + u32 sc_smctr; + u32 sc_lmaer; + u8 res3[4]; + u32 sc_lmevr; + u32 sc_lmctr; + u8 res4[144]; +} sysconf_85xx_cpm2_t; + +typedef union sys_conf { + sysconf_82xx_cpm2_t siu_82xx; + sysconf_85xx_cpm2_t siu_85xx; +} sysconf_cpm2_t; + + + +/* Memory controller registers. +*/ +typedef struct mem_ctlr { + u32 memc_br0; + u32 memc_or0; + u32 memc_br1; + u32 memc_or1; + u32 memc_br2; + u32 memc_or2; + u32 memc_br3; + u32 memc_or3; + u32 memc_br4; + u32 memc_or4; + u32 memc_br5; + u32 memc_or5; + u32 memc_br6; + u32 memc_or6; + u32 memc_br7; + u32 memc_or7; + u32 memc_br8; + u32 memc_or8; + u32 memc_br9; + u32 memc_or9; + u32 memc_br10; + u32 memc_or10; + u32 memc_br11; + u32 memc_or11; + u8 res1[8]; + u32 memc_mar; + u8 res2[4]; + u32 memc_mamr; + u32 memc_mbmr; + u32 memc_mcmr; + u8 res3[8]; + u16 memc_mptpr; + u8 res4[2]; + u32 memc_mdr; + u8 res5[4]; + u32 memc_psdmr; + u32 memc_lsdmr; + u8 memc_purt; + u8 res6[3]; + u8 memc_psrt; + u8 res7[3]; + u8 memc_lurt; + u8 res8[3]; + u8 memc_lsrt; + u8 res9[3]; + u32 memc_immr; + u32 memc_pcibr0; + u32 memc_pcibr1; + u8 res10[16]; + u32 memc_pcimsk0; + u32 memc_pcimsk1; + u8 res11[52]; +} memctl_cpm2_t; + +/* System Integration Timers. +*/ +typedef struct sys_int_timers { + u8 res1[32]; + u16 sit_tmcntsc; + u8 res2[2]; + u32 sit_tmcnt; + u8 res3[4]; + u32 sit_tmcntal; + u8 res4[16]; + u16 sit_piscr; + u8 res5[2]; + u32 sit_pitc; + u32 sit_pitr; + u8 res6[92]; + u8 res7[390]; +} sit_cpm2_t; + +#define PISCR_PIRQ_MASK ((u16)0xff00) +#define PISCR_PS ((u16)0x0080) +#define PISCR_PIE ((u16)0x0004) +#define PISCR_PTF ((u16)0x0002) +#define PISCR_PTE ((u16)0x0001) + +/* PCI Controller. +*/ +typedef struct pci_ctlr { + u32 pci_omisr; + u32 pci_omimr; + u8 res1[8]; + u32 pci_ifqpr; + u32 pci_ofqpr; + u8 res2[8]; + u32 pci_imr0; + u32 pci_imr1; + u32 pci_omr0; + u32 pci_omr1; + u32 pci_odr; + u8 res3[4]; + u32 pci_idr; + u8 res4[20]; + u32 pci_imisr; + u32 pci_imimr; + u8 res5[24]; + u32 pci_ifhpr; + u8 res6[4]; + u32 pci_iftpr; + u8 res7[4]; + u32 pci_iphpr; + u8 res8[4]; + u32 pci_iptpr; + u8 res9[4]; + u32 pci_ofhpr; + u8 res10[4]; + u32 pci_oftpr; + u8 res11[4]; + u32 pci_ophpr; + u8 res12[4]; + u32 pci_optpr; + u8 res13[8]; + u32 pci_mucr; + u8 res14[8]; + u32 pci_qbar; + u8 res15[12]; + u32 pci_dmamr0; + u32 pci_dmasr0; + u32 pci_dmacdar0; + u8 res16[4]; + u32 pci_dmasar0; + u8 res17[4]; + u32 pci_dmadar0; + u8 res18[4]; + u32 pci_dmabcr0; + u32 pci_dmandar0; + u8 res19[86]; + u32 pci_dmamr1; + u32 pci_dmasr1; + u32 pci_dmacdar1; + u8 res20[4]; + u32 pci_dmasar1; + u8 res21[4]; + u32 pci_dmadar1; + u8 res22[4]; + u32 pci_dmabcr1; + u32 pci_dmandar1; + u8 res23[88]; + u32 pci_dmamr2; + u32 pci_dmasr2; + u32 pci_dmacdar2; + u8 res24[4]; + u32 pci_dmasar2; + u8 res25[4]; + u32 pci_dmadar2; + u8 res26[4]; + u32 pci_dmabcr2; + u32 pci_dmandar2; + u8 res27[88]; + u32 pci_dmamr3; + u32 pci_dmasr3; + u32 pci_dmacdar3; + u8 res28[4]; + u32 pci_dmasar3; + u8 res29[4]; + u32 pci_dmadar3; + u8 res30[4]; + u32 pci_dmabcr3; + u32 pci_dmandar3; + u8 res31[344]; + u32 pci_potar0; + u8 res32[4]; + u32 pci_pobar0; + u8 res33[4]; + u32 pci_pocmr0; + u8 res34[4]; + u32 pci_potar1; + u8 res35[4]; + u32 pci_pobar1; + u8 res36[4]; + u32 pci_pocmr1; + u8 res37[4]; + u32 pci_potar2; + u8 res38[4]; + u32 pci_pobar2; + u8 res39[4]; + u32 pci_pocmr2; + u8 res40[50]; + u32 pci_ptcr; + u32 pci_gpcr; + u32 pci_gcr; + u32 pci_esr; + u32 pci_emr; + u32 pci_ecr; + u32 pci_eacr; + u8 res41[4]; + u32 pci_edcr; + u8 res42[4]; + u32 pci_eccr; + u8 res43[44]; + u32 pci_pitar1; + u8 res44[4]; + u32 pci_pibar1; + u8 res45[4]; + u32 pci_picmr1; + u8 res46[4]; + u32 pci_pitar0; + u8 res47[4]; + u32 pci_pibar0; + u8 res48[4]; + u32 pci_picmr0; + u8 res49[4]; + u32 pci_cfg_addr; + u32 pci_cfg_data; + u32 pci_int_ack; + u8 res50[756]; +} pci_cpm2_t; + +/* Interrupt Controller. +*/ +typedef struct interrupt_controller { + u16 ic_sicr; + u8 res1[2]; + u32 ic_sivec; + u32 ic_sipnrh; + u32 ic_sipnrl; + u32 ic_siprr; + u32 ic_scprrh; + u32 ic_scprrl; + u32 ic_simrh; + u32 ic_simrl; + u32 ic_siexr; + u8 res2[88]; +} intctl_cpm2_t; + +/* Clocks and Reset. +*/ +typedef struct clk_and_reset { + u32 car_sccr; + u8 res1[4]; + u32 car_scmr; + u8 res2[4]; + u32 car_rsr; + u32 car_rmr; + u8 res[104]; +} car_cpm2_t; + +/* Input/Output Port control/status registers. + * Names consistent with processor manual, although they are different + * from the original 8xx names....... + */ +typedef struct io_port { + u32 iop_pdira; + u32 iop_ppara; + u32 iop_psora; + u32 iop_podra; + u32 iop_pdata; + u8 res1[12]; + u32 iop_pdirb; + u32 iop_pparb; + u32 iop_psorb; + u32 iop_podrb; + u32 iop_pdatb; + u8 res2[12]; + u32 iop_pdirc; + u32 iop_pparc; + u32 iop_psorc; + u32 iop_podrc; + u32 iop_pdatc; + u8 res3[12]; + u32 iop_pdird; + u32 iop_ppard; + u32 iop_psord; + u32 iop_podrd; + u32 iop_pdatd; + u8 res4[12]; +} iop_cpm2_t; + +/* Communication Processor Module Timers +*/ +typedef struct cpm_timers { + u8 cpmt_tgcr1; + u8 res1[3]; + u8 cpmt_tgcr2; + u8 res2[11]; + u16 cpmt_tmr1; + u16 cpmt_tmr2; + u16 cpmt_trr1; + u16 cpmt_trr2; + u16 cpmt_tcr1; + u16 cpmt_tcr2; + u16 cpmt_tcn1; + u16 cpmt_tcn2; + u16 cpmt_tmr3; + u16 cpmt_tmr4; + u16 cpmt_trr3; + u16 cpmt_trr4; + u16 cpmt_tcr3; + u16 cpmt_tcr4; + u16 cpmt_tcn3; + u16 cpmt_tcn4; + u16 cpmt_ter1; + u16 cpmt_ter2; + u16 cpmt_ter3; + u16 cpmt_ter4; + u8 res3[584]; +} cpmtimer_cpm2_t; + +/* DMA control/status registers. +*/ +typedef struct sdma_csr { + u8 res0[24]; + u8 sdma_sdsr; + u8 res1[3]; + u8 sdma_sdmr; + u8 res2[3]; + u8 sdma_idsr1; + u8 res3[3]; + u8 sdma_idmr1; + u8 res4[3]; + u8 sdma_idsr2; + u8 res5[3]; + u8 sdma_idmr2; + u8 res6[3]; + u8 sdma_idsr3; + u8 res7[3]; + u8 sdma_idmr3; + u8 res8[3]; + u8 sdma_idsr4; + u8 res9[3]; + u8 sdma_idmr4; + u8 res10[707]; +} sdma_cpm2_t; + +/* Fast controllers +*/ +typedef struct fcc { + u32 fcc_gfmr; + u32 fcc_fpsmr; + u16 fcc_ftodr; + u8 res1[2]; + u16 fcc_fdsr; + u8 res2[2]; + u16 fcc_fcce; + u8 res3[2]; + u16 fcc_fccm; + u8 res4[2]; + u8 fcc_fccs; + u8 res5[3]; + u8 fcc_ftirr_phy[4]; +} fcc_t; + +/* Fast controllers continued + */ +typedef struct fcc_c { + u32 fcc_firper; + u32 fcc_firer; + u32 fcc_firsr_hi; + u32 fcc_firsr_lo; + u8 fcc_gfemr; + u8 res1[15]; +} fcc_c_t; + +/* TC Layer + */ +typedef struct tclayer { + u16 tc_tcmode; + u16 tc_cdsmr; + u16 tc_tcer; + u16 tc_rcc; + u16 tc_tcmr; + u16 tc_fcc; + u16 tc_ccc; + u16 tc_icc; + u16 tc_tcc; + u16 tc_ecc; + u8 res1[12]; +} tclayer_t; + + +/* I2C +*/ +typedef struct i2c { + u8 i2c_i2mod; + u8 res1[3]; + u8 i2c_i2add; + u8 res2[3]; + u8 i2c_i2brg; + u8 res3[3]; + u8 i2c_i2com; + u8 res4[3]; + u8 i2c_i2cer; + u8 res5[3]; + u8 i2c_i2cmr; + u8 res6[331]; +} i2c_cpm2_t; + +typedef struct scc { /* Serial communication channels */ + u32 scc_gsmrl; + u32 scc_gsmrh; + u16 scc_psmr; + u8 res1[2]; + u16 scc_todr; + u16 scc_dsr; + u16 scc_scce; + u8 res2[2]; + u16 scc_sccm; + u8 res3; + u8 scc_sccs; + u8 res4[8]; +} scc_t; + +typedef struct smc { /* Serial management channels */ + u8 res1[2]; + u16 smc_smcmr; + u8 res2[2]; + u8 smc_smce; + u8 res3[3]; + u8 smc_smcm; + u8 res4[5]; +} smc_t; + +/* Serial Peripheral Interface. +*/ +typedef struct spi_ctrl { + u16 spi_spmode; + u8 res1[4]; + u8 spi_spie; + u8 res2[3]; + u8 spi_spim; + u8 res3[2]; + u8 spi_spcom; + u8 res4[82]; +} spictl_cpm2_t; + +/* CPM Mux. +*/ +typedef struct cpmux { + u8 cmx_si1cr; + u8 res1; + u8 cmx_si2cr; + u8 res2; + u32 cmx_fcr; + u32 cmx_scr; + u8 cmx_smr; + u8 res3; + u16 cmx_uar; + u8 res4[16]; +} cpmux_t; + +/* SIRAM control +*/ +typedef struct siram { + u16 si_amr; + u16 si_bmr; + u16 si_cmr; + u16 si_dmr; + u8 si_gmr; + u8 res1; + u8 si_cmdr; + u8 res2; + u8 si_str; + u8 res3; + u16 si_rsr; +} siramctl_t; + +typedef struct mcc { + u16 mcc_mcce; + u8 res1[2]; + u16 mcc_mccm; + u8 res2[2]; + u8 mcc_mccf; + u8 res3[7]; +} mcc_t; + +typedef struct comm_proc { + u32 cp_cpcr; + u32 cp_rccr; + u8 res1[14]; + u16 cp_rter; + u8 res2[2]; + u16 cp_rtmr; + u16 cp_rtscr; + u8 res3[2]; + u32 cp_rtsr; + u8 res4[12]; +} cpm_cpm2_t; + +/* USB Controller. +*/ +typedef struct usb_ctlr { + u8 usb_usmod; + u8 usb_usadr; + u8 usb_uscom; + u8 res1[1]; + u16 usb_usep1; + u16 usb_usep2; + u16 usb_usep3; + u16 usb_usep4; + u8 res2[4]; + u16 usb_usber; + u8 res3[2]; + u16 usb_usbmr; + u8 usb_usbs; + u8 res4[7]; +} usb_cpm2_t; + +/* ...and the whole thing wrapped up.... +*/ + +typedef struct immap { + /* Some references are into the unique and known dpram spaces, + * others are from the generic base. + */ +#define im_dprambase im_dpram1 + u8 im_dpram1[16*1024]; + u8 res1[16*1024]; + u8 im_dpram2[4*1024]; + u8 res2[8*1024]; + u8 im_dpram3[4*1024]; + u8 res3[16*1024]; + + sysconf_cpm2_t im_siu_conf; /* SIU Configuration */ + memctl_cpm2_t im_memctl; /* Memory Controller */ + sit_cpm2_t im_sit; /* System Integration Timers */ + pci_cpm2_t im_pci; /* PCI Controller */ + intctl_cpm2_t im_intctl; /* Interrupt Controller */ + car_cpm2_t im_clkrst; /* Clocks and reset */ + iop_cpm2_t im_ioport; /* IO Port control/status */ + cpmtimer_cpm2_t im_cpmtimer; /* CPM timers */ + sdma_cpm2_t im_sdma; /* SDMA control/status */ + + fcc_t im_fcc[3]; /* Three FCCs */ + u8 res4z[32]; + fcc_c_t im_fcc_c[3]; /* Continued FCCs */ + + u8 res4[32]; + + tclayer_t im_tclayer[8]; /* Eight TCLayers */ + u16 tc_tcgsr; + u16 tc_tcger; + + /* First set of baud rate generators. + */ + u8 res[236]; + u32 im_brgc5; + u32 im_brgc6; + u32 im_brgc7; + u32 im_brgc8; + + u8 res5[608]; + + i2c_cpm2_t im_i2c; /* I2C control/status */ + cpm_cpm2_t im_cpm; /* Communication processor */ + + /* Second set of baud rate generators. + */ + u32 im_brgc1; + u32 im_brgc2; + u32 im_brgc3; + u32 im_brgc4; + + scc_t im_scc[4]; /* Four SCCs */ + smc_t im_smc[2]; /* Couple of SMCs */ + spictl_cpm2_t im_spi; /* A SPI */ + cpmux_t im_cpmux; /* CPM clock route mux */ + siramctl_t im_siramctl1; /* First SI RAM Control */ + mcc_t im_mcc1; /* First MCC */ + siramctl_t im_siramctl2; /* Second SI RAM Control */ + mcc_t im_mcc2; /* Second MCC */ + usb_cpm2_t im_usb; /* USB Controller */ + + u8 res6[1153]; + + u16 im_si1txram[256]; + u8 res7[512]; + u16 im_si1rxram[256]; + u8 res8[512]; + u16 im_si2txram[256]; + u8 res9[512]; + u16 im_si2rxram[256]; + u8 res10[512]; + u8 res11[4096]; +} cpm2_map_t; + +extern cpm2_map_t *cpm2_immr; + +#endif /* __IMMAP_CPM2__ */ +#endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/asm-ppc/mpc8260.h linux-2.4.26/include/asm-ppc/mpc8260.h --- linux-2.4.25/include/asm-ppc/mpc8260.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-ppc/mpc8260.h 2004-04-14 06:05:40.000000000 -0700 @@ -12,10 +12,18 @@ #ifdef CONFIG_8260 +#ifdef CONFIG_RPX6 +#include +#endif + #ifdef CONFIG_EST8260 #include #endif +#ifdef CONFIG_PQ2ADS +#include +#endif + /* I don't yet have the ISA or PCI stuff done....no 8260 with * such thing..... */ diff -urN linux-2.4.25/include/asm-ppc/ocp.h linux-2.4.26/include/asm-ppc/ocp.h --- linux-2.4.25/include/asm-ppc/ocp.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/ocp.h 2004-04-14 06:05:40.000000000 -0700 @@ -4,7 +4,7 @@ * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org) * Mipsys - France * - " Derived from work (c) Armin Kuster akuster@pacbell.net + * Derived from work (c) Armin Kuster akuster@pacbell.net * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -36,6 +36,7 @@ #ifndef __OCP_H__ #define __OCP_H__ +#include #include #include #include @@ -49,6 +50,10 @@ #include #endif +#if defined(CONFIG_MPC_OCP) +#include +#endif + #define OCP_MAX_IRQS 7 #define MAX_EMACS 4 #define OCP_IRQ_NA -1 /* used when ocp device does not have an irq */ @@ -115,7 +120,7 @@ struct ocp_device { struct list_head link; char name[80]; /* device name */ - const struct ocp_def *def; /* device definition */ + struct ocp_def *def; /* device definition */ void *drvdata; /* driver data for this device */ struct ocp_driver *driver; u32 current_state; /* Current operating state. In ACPI-speak, @@ -180,12 +185,23 @@ extern int ocp_register_driver(struct ocp_driver *drv); extern void ocp_unregister_driver(struct ocp_driver *drv); -/* Initialize the OCP management layer */ -extern int ocp_init(void); +/* Build list of devices */ +extern int ocp_early_init(void) __init; + +/* Initialize the driver portion of OCP management layer */ +extern int ocp_driver_init(void); /* Find a device by index */ extern struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index); +/* Get a def by index */ +extern struct ocp_def *ocp_get_one_device(unsigned int vendor, unsigned int function, int index); + +/* Add a device by index */ +extern int ocp_add_one_device(struct ocp_def *def); + +/* Remove a device by index */ +extern int ocp_remove_one_device(unsigned int vendor, unsigned int function, int index); #endif /* __OCP_H__ */ #endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/asm-ppc/ocp_ids.h linux-2.4.26/include/asm-ppc/ocp_ids.h --- linux-2.4.25/include/asm-ppc/ocp_ids.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/asm-ppc/ocp_ids.h 2004-04-14 06:05:40.000000000 -0700 @@ -52,26 +52,17 @@ #define OCP_FUNC_INVALID 0x0000 /* system 0x0001 - 0x001F */ -#define OCP_FUNC_UIC 0x0001 /* Timers 0x0020 - 0x002F */ -#define OCP_FUNC_GPT 0x0020 /* General purpose timers */ -#define OCP_FUNC_RTC 0x0021 /* Serial 0x0030 - 0x006F*/ #define OCP_FUNC_16550 0x0031 -#define OCP_FUNC_SSP 0x0032 /* sync serial port */ -#define OCP_FUNC_SCP 0x0033 /* serial controller port */ -#define OCP_FUNC_SCC 0x0034 /* serial contoller */ -#define OCP_FUNC_SCI 0x0035 /* Smart card */ -#define OCP_FUNC_IIC 0x0040 -#define OCP_FUNC_USB 0x0050 -#define OCP_FUNC_IR 0x0060 +#define OCP_FUNC_IIC 0x0032 +#define OCP_FUNC_USB 0x0033 /* Memory devices 0x0090 - 0x009F */ -#define OCP_FUNC_SDRAM 0x0091 -#define OCP_FUNC_DMA 0x0092 -#define OCP_FUNC_MAL 0x0093 +#define OCP_FUNC_MAL 0x0090 +#define OCP_FUNC_DMA 0x0091 /* Additional data */ struct ocp_func_mal_data { @@ -80,12 +71,8 @@ }; /* Display 0x00A0 - 0x00AF */ -#define OCP_FUNC_VIDEO 0x00A0 -#define OCP_FUNC_LED 0x00A1 -#define OCP_FUNC_LCD 0x00A2 /* Sound 0x00B0 - 0x00BF */ -#define OCP_FUNC_AUDIO 0x00B0 /* Mass Storage 0x00C0 - 0xxCF */ #define OCP_FUNC_IDE 0x00C0 @@ -93,9 +80,11 @@ /* Misc 0x00D0 - 0x00DF*/ #define OCP_FUNC_GPIO 0x00D0 #define OCP_FUNC_ZMII 0x00D1 +#define OCP_FUNC_PERFMON 0x00D2 /* Performance Monitor */ /* Network 0x0200 - 0x02FF */ #define OCP_FUNC_EMAC 0x0200 +#define OCP_FUNC_GFAR 0x0201 /* TSEC & FEC */ /* Additional data * @@ -115,12 +104,6 @@ }; /* Bridge devices 0xE00 - 0xEFF */ -#define OCP_FUNC_HOST 0x0E00 -#define OCP_FUNC_DCR 0x0E01 -#define OCP_FUNC_OPB 0x0E02 -#define OCP_FUNC_PHY 0x0E03 -#define OCP_FUNC_EXT 0x0E04 -#define OCP_FUNC_PCI 0x0E05 -#define OCP_FUNC_PLB 0x0E06 +#define OCP_FUNC_OPB 0x0E00 #define OCP_FUNC_UNKNOWN 0xFFFF diff -urN linux-2.4.25/include/asm-ppc/ppc_asm.h linux-2.4.26/include/asm-ppc/ppc_asm.h --- linux-2.4.25/include/asm-ppc/ppc_asm.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/ppc_asm.h 2004-04-14 06:05:40.000000000 -0700 @@ -163,6 +163,8 @@ #define CLR_TOP32(r) #endif /* CONFIG_PPC64BRIDGE */ +#define RFMCI .long 0x4c00004c /* rfmci instruction */ + #ifdef CONFIG_IBM405_ERR77 #define PPC405_ERR77(ra,rb) dcbt ra, rb; #define PPC405_ERR77_SYNC sync; diff -urN linux-2.4.25/include/asm-ppc/ppcboot.h linux-2.4.26/include/asm-ppc/ppcboot.h --- linux-2.4.25/include/asm-ppc/ppcboot.h 2001-11-02 17:43:54.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/ppcboot.h 2004-04-14 06:05:40.000000000 -0700 @@ -52,7 +52,7 @@ unsigned long bi_flashoffset; /* reserved area for startup monitor */ unsigned long bi_sramstart; /* start of SRAM memory */ unsigned long bi_sramsize; /* size of SRAM memory */ -#if defined(CONFIG_8xx) || defined(CONFIG_8260) +#if defined(CONFIG_8xx) || defined(CONFIG_CPM2) unsigned long bi_immr_base; /* base of IMMR register */ #endif unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */ @@ -61,7 +61,7 @@ unsigned short bi_ethspeed; /* Ethernet speed in Mbps */ unsigned long bi_intfreq; /* Internal Freq, in MHz */ unsigned long bi_busfreq; /* Bus Freq, in MHz */ -#if defined(CONFIG_8260) +#if defined(CONFIG_CPM2) unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */ unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */ unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */ diff -urN linux-2.4.25/include/asm-ppc/processor.h linux-2.4.26/include/asm-ppc/processor.h --- linux-2.4.25/include/asm-ppc/processor.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-ppc/processor.h 2004-04-14 06:05:40.000000000 -0700 @@ -544,10 +544,22 @@ #define SPRN_IVOR13 0x19d /* Interrupt Vector Offset Register 13 */ #define SPRN_IVOR14 0x19e /* Interrupt Vector Offset Register 14 */ #define SPRN_IVOR15 0x19f /* Interrupt Vector Offset Register 15 */ +#define SPRN_MCSRR0 0x23a /* Machine Check Save and Restore Register 0 */ +#define SPRN_MCSRR1 0x23b /* Machine Check Save and Restore Register 1 */ +#define SPRN_MCSR 0x23c /* Machine Check Syndrom Register */ +#if defined(CONFIG_440A) +#define MCSR_MCS 0x80000000 /* Machine Check Summary */ +#define MCSR_IB 0x40000000 /* Instruction PLB Error */ +#define MCSR_DRB 0x20000000 /* Data Read PLB Error */ +#define MCSR_DWB 0x10000000 /* Data Write PLB Error */ +#define MCSR_TLBP 0x08000000 /* TLB Parity Error */ +#define MCSR_ICP 0x04000000 /* I-Cache Parity Error */ +#define MCSR_DCSP 0x02000000 /* D-Cache Search Parity Error */ +#define MCSR_DCFP 0x01000000 /* D-Cache Flush Parity Error */ +#define MCSR_IMPE 0x00800000 /* Imprecise Machine Check Exception */ +#endif #define SPRN_MMUCR 0x3b2 /* MMU Control Register */ -#define ESR_ST 0x00800000 /* Store Operation */ - /* Short-hand versions for a number of the above SPRNs */ #define CTR SPRN_CTR /* Counter Register */ @@ -664,7 +676,9 @@ #define PVR_440GP_RB 0x40120440 #define PVR_440GP_RC1 0x40120481 #define PVR_440GP_RC2 0x40200481 -#define PVR_440GX_RC1 0x51b21850 +#define PVR_440GX_RA 0x51b21850 +#define PVR_440GX_RB 0x51b21851 +#define PVR_440GX_RB1 0x51b21852 #define PVR_601 0x00010000 #define PVR_602 0x00050000 #define PVR_603 0x00030000 @@ -714,6 +728,7 @@ #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ #define _GLOBAL(n)\ + .stabs __stringify(n:F-1),N_FUN,0,0,n;\ .globl n;\ n: diff -urN linux-2.4.25/include/asm-x86_64/acpi.h linux-2.4.26/include/asm-x86_64/acpi.h --- linux-2.4.25/include/asm-x86_64/acpi.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/acpi.h 2004-04-14 06:05:40.000000000 -0700 @@ -52,40 +52,35 @@ #define ACPI_ENABLE_IRQS() __sti() #define ACPI_FLUSH_CPU_CACHE() wbinvd() -/* - * A brief explanation as GNU inline assembly is a bit hairy - * %0 is the output parameter in RAX ("=a") - * %1 and %2 are the input parameters in RCX ("c") - * and an immediate value ("i") respectively - * All actual register references are preceded with "%%" as in "%%edx" - * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter are the operation altered non-output registers. - */ +static inline int +__acpi_acquire_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return (new < 3) ? -1 : 0; +} + +static inline int +__acpi_release_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = old & ~0x3; + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return old & 0x1; +} + #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - unsigned long dummy; \ - asm("1: movl (%2),%%eax;" \ - "movl %%eax,%%edx;" \ - "andq %2,%%rdx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ - } while(0) + ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr)) + #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - unsigned long dummy; \ - asm("1: movl (%2),%%eax;" \ - "movl %%eax,%%edx;" \ - "andq %2,%%rdx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ - } while(0) + ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr)) /* * Math helper asm macros @@ -108,6 +103,10 @@ extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; +extern int acpi_strict; +extern int acpi_disabled; +extern int acpi_ht; +static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; } /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 @@ -142,8 +141,6 @@ #define boot_cpu_physical_apicid boot_cpu_id -extern void mp_config_ioapic_for_sci(int irq); - #endif /*__KERNEL__*/ #endif /*_ASM_ACPI_H*/ diff -urN linux-2.4.25/include/asm-x86_64/cpufeature.h linux-2.4.26/include/asm-x86_64/cpufeature.h --- linux-2.4.25/include/asm-x86_64/cpufeature.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/cpufeature.h 2004-04-14 06:05:40.000000000 -0700 @@ -10,7 +10,7 @@ /* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */ #define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT) -#define NCAPINTS 4 /* Currently we have 4 32-bit words worth of info */ +#define NCAPINTS 5 /* Currently we have 5 32-bit words worth of info */ /* Intel-defined CPU features, CPUID level 0x00000001, word 0 */ #define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */ @@ -40,8 +40,10 @@ #define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */ #define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */ #define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */ +#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */ #define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */ #define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */ +#define X86_FEATURE_PBE (0*32+31) /* Pending Break Enable */ /* AMD-defined CPU features, CPUID level 0x80000001, word 1 */ /* Don't duplicate feature flags which are redundant with Intel! */ @@ -62,6 +64,24 @@ #define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */ #define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */ #define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */ +/* cpu types for specific tunings: */ +#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */ +#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */ +#define X86_FEATURE_P3 (3*32+ 6) /* P3 */ +#define X86_FEATURE_P4 (3*32+ 7) /* P4 */ + + +/* Intel-defined CPU features, CPUID level 0x00000001, ecx, word 4 */ +#define X86_FEATURE_PNI (4*32+ 0) /* Streaming SIMD Extensions 3 */ +#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor-Mwait Support */ +#define X86_FEATURE_DS_CPL (4*32+ 4) /* CPL qualified debug store */ +#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */ +#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal monitor 2 */ +#define X86_FEATURE_CNXT_ID (4*32+ 10) /* L1 Context ID */ + +#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) +#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) + #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) #define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability) @@ -75,7 +95,7 @@ #define cpu_has_fxsr 1 #define cpu_has_xmm 1 #define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC) -#define cpu_has_ht 0 +#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT) #define cpu_has_mp boot_cpu_has(X86_FEATURE_MP) #define cpu_has_k6_mtrr 0 #define cpu_has_cyrix_arr 0 diff -urN linux-2.4.25/include/asm-x86_64/mpspec.h linux-2.4.26/include/asm-x86_64/mpspec.h --- linux-2.4.25/include/asm-x86_64/mpspec.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/asm-x86_64/mpspec.h 2004-04-14 06:05:40.000000000 -0700 @@ -196,7 +196,6 @@ extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base); extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); extern void mp_config_acpi_legacy_irqs (void); -extern void mp_config_ioapic_for_sci(int irq); extern void mp_parse_prt (void); #endif /*CONFIG_X86_IO_APIC*/ diff -urN linux-2.4.25/include/asm-x86_64/pci-direct.h linux-2.4.26/include/asm-x86_64/pci-direct.h --- linux-2.4.25/include/asm-x86_64/pci-direct.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/asm-x86_64/pci-direct.h 2004-04-14 06:05:40.000000000 -0700 @@ -28,7 +28,7 @@ return v; } -static inline u8 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) +static inline u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) { u16 v; outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); diff -urN linux-2.4.25/include/asm-x86_64/pci.h linux-2.4.26/include/asm-x86_64/pci.h --- linux-2.4.25/include/asm-x86_64/pci.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/pci.h 2004-04-14 06:05:40.000000000 -0700 @@ -65,6 +65,18 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); +#ifdef CONFIG_SWIOTLB +extern int swiotlb; +extern dma_addr_t swiotlb_map_single (struct pci_dev *hwdev, void *ptr, size_t size, + int dir); +extern void swiotlb_unmap_single (struct pci_dev *hwdev, dma_addr_t dev_addr, + size_t size, int dir); +extern void swiotlb_sync_single (struct pci_dev *hwdev, dma_addr_t dev_addr, + size_t size, int dir); +extern void swiotlb_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, + int dir); +#endif + #ifdef CONFIG_GART_IOMMU /* Map a single buffer of the indicated size for DMA in streaming mode. @@ -105,6 +117,10 @@ dma_addr_t dma_handle, size_t size, int direction) { +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_sync_single(hwdev,dma_handle,size,direction); +#endif BUG_ON(direction == PCI_DMA_NONE); } @@ -113,6 +129,10 @@ int nelems, int direction) { BUG_ON(direction == PCI_DMA_NONE); +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_sync_sg(hwdev,sg,nelems,direction); +#endif } /* The PCI address space does equal the physical memory diff -urN linux-2.4.25/include/asm-x86_64/pgtable.h linux-2.4.26/include/asm-x86_64/pgtable.h --- linux-2.4.25/include/asm-x86_64/pgtable.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/asm-x86_64/pgtable.h 2004-04-14 06:05:40.000000000 -0700 @@ -79,7 +79,7 @@ * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern unsigned long empty_zero_page[1024]; +extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) #endif /* !__ASSEMBLY__ */ diff -urN linux-2.4.25/include/asm-x86_64/processor.h linux-2.4.26/include/asm-x86_64/processor.h --- linux-2.4.25/include/asm-x86_64/processor.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/processor.h 2004-04-14 06:05:40.000000000 -0700 @@ -400,13 +400,40 @@ } #define ARCH_HAS_PREFETCH -#define ARCH_HAS_PREFETCHW #define ARCH_HAS_SPINLOCK_PREFETCH -#define prefetch(x) __builtin_prefetch((x),0) +#ifdef CONFIG_MK8 +#define ARCH_HAS_PREFETCHW #define prefetchw(x) __builtin_prefetch((x),1) #define spin_lock_prefetch(x) prefetchw(x) +#else +#define spin_lock_prefetch(x) prefetch(x) +#endif + +#define prefetch(x) __builtin_prefetch((x),0) + #define cpu_relax() rep_nop() +static __inline__ void __monitor(const void *eax, unsigned long ecx, + unsigned long edx) +{ + /* "monitor %eax,%ecx,%edx;" */ + asm volatile( + ".byte 0x0f,0x01,0xc8;" + : :"a" (eax), "c" (ecx), "d"(edx)); +} + +static __inline__ void __mwait(unsigned long eax, unsigned long ecx) +{ + /* "mwait %eax,%ecx;" */ + asm volatile( + ".byte 0x0f,0x01,0xc9;" + : :"a" (eax), "c" (ecx)); +} + +#define ARCH_HAS_SMP_BALANCE 1 + #endif /* __ASM_X86_64_PROCESSOR_H */ + + diff -urN linux-2.4.25/include/asm-x86_64/proto.h linux-2.4.26/include/asm-x86_64/proto.h --- linux-2.4.25/include/asm-x86_64/proto.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/proto.h 2004-04-14 06:05:40.000000000 -0700 @@ -25,6 +25,8 @@ extern void do_softirq_thunk(void); +extern void swiotlb_init(void); + extern int setup_early_printk(char *); extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2))); @@ -36,7 +38,10 @@ extern void reserve_bootmem_generic(unsigned long phys, unsigned len); extern void free_bootmem_generic(unsigned long phys, unsigned len); +extern void check_efer(void); + extern unsigned long start_pfn, end_pfn, end_pfn_map; +extern int iommu_aperture; extern void show_stack(unsigned long * rsp); extern void show_trace(unsigned long *stack); @@ -44,7 +49,6 @@ extern void show_regs(struct pt_regs * regs); extern int apic_disabled; -extern int acpi_disabled; #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1)) #define round_down(x,y) ((x) & ~((y)-1)) diff -urN linux-2.4.25/include/asm-x86_64/scatterlist.h linux-2.4.26/include/asm-x86_64/scatterlist.h --- linux-2.4.25/include/asm-x86_64/scatterlist.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/asm-x86_64/scatterlist.h 2004-04-14 06:05:40.000000000 -0700 @@ -9,6 +9,7 @@ unsigned int length; dma_addr_t dma_address; + unsigned int dma_length; }; #define ISA_DMA_THRESHOLD (0x00ffffff) diff -urN linux-2.4.25/include/asm-x86_64/smp.h linux-2.4.26/include/asm-x86_64/smp.h --- linux-2.4.25/include/asm-x86_64/smp.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/smp.h 2004-04-14 06:05:40.000000000 -0700 @@ -36,6 +36,9 @@ extern unsigned long cpu_online_map; extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; +extern int smp_num_siblings; +extern int cpu_sibling_map[]; + extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); @@ -89,8 +92,8 @@ return GET_APIC_ID(*(unsigned *)(APIC_BASE+APIC_ID)); } -/* Assume apicid == cpuid */ -#define safe_smp_processor_id() (cpuid_ebx(1) >> 24) +extern int apic_disabled; +#define safe_smp_processor_id() (apic_disabled ? 0 : x86_apicid_to_cpu[hard_smp_processor_id()]) #endif /* !ASSEMBLY */ diff -urN linux-2.4.25/include/asm-x86_64/uaccess.h linux-2.4.26/include/asm-x86_64/uaccess.h --- linux-2.4.25/include/asm-x86_64/uaccess.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/asm-x86_64/uaccess.h 2004-04-14 06:05:40.000000000 -0700 @@ -236,6 +236,7 @@ extern unsigned long copy_to_user(void *to, const void *from, unsigned len); extern unsigned long copy_from_user(void *to, const void *from, unsigned len); +extern unsigned long copy_in_user(void *to, const void *from, unsigned len); static inline int __copy_from_user(void *dst, const void *src, unsigned size) { diff -urN linux-2.4.25/include/linux/compiler.h linux-2.4.26/include/linux/compiler.h --- linux-2.4.25/include/linux/compiler.h 2001-09-18 14:12:45.000000000 -0700 +++ linux-2.4.26/include/linux/compiler.h 2004-04-14 06:05:40.000000000 -0700 @@ -13,4 +13,18 @@ #define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0) +#if __GNUC__ > 3 +#define __attribute_used__ __attribute((__used__)) +#elif __GNUC__ == 3 +#if __GNUC_MINOR__ >= 3 +# define __attribute_used__ __attribute__((__used__)) +#else +# define __attribute_used__ __attribute__((__unused__)) +#endif /* __GNUC_MINOR__ >= 3 */ +#elif __GNUC__ == 2 +#define __attribute_used__ __attribute__((__unused__)) +#else +#define __attribute_used__ /* not implemented */ +#endif /* __GNUC__ */ + #endif /* __LINUX_COMPILER_H */ diff -urN linux-2.4.25/include/linux/hiddev.h linux-2.4.26/include/linux/hiddev.h --- linux-2.4.25/include/linux/hiddev.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/linux/hiddev.h 2004-04-14 06:05:40.000000000 -0700 @@ -39,33 +39,33 @@ }; struct hiddev_devinfo { - unsigned int bustype; - unsigned int busnum; - unsigned int devnum; - unsigned int ifnum; - short vendor; - short product; - short version; - unsigned num_applications; + __u32 bustype; + __u32 busnum; + __u32 devnum; + __u32 ifnum; + __s16 vendor; + __s16 product; + __s16 version; + __u32 num_applications; }; struct hiddev_collection_info { - unsigned index; - unsigned type; - unsigned usage; - unsigned level; + __u32 index; + __u32 type; + __u32 usage; + __u32 level; }; #define HID_STRING_SIZE 256 struct hiddev_string_descriptor { - int index; + __s32 index; char value[HID_STRING_SIZE]; }; struct hiddev_report_info { - unsigned report_type; - unsigned report_id; - unsigned num_fields; + __u32 report_type; + __u32 report_id; + __u32 num_fields; }; /* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and @@ -88,20 +88,20 @@ #define HID_REPORT_TYPE_MAX 3 struct hiddev_field_info { - unsigned report_type; - unsigned report_id; - unsigned field_index; - unsigned maxusage; - unsigned flags; - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ + __u32 report_type; + __u32 report_id; + __u32 field_index; + __u32 maxusage; + __u32 flags; + __u32 physical; /* physical usage for this field */ + __u32 logical; /* logical usage for this field */ + __u32 application; /* application usage for this field */ __s32 logical_minimum; __s32 logical_maximum; __s32 physical_minimum; __s32 physical_maximum; - unsigned unit_exponent; - unsigned unit; + __u32 unit_exponent; + __u32 unit; }; /* Fill in report_type, report_id and field_index to get the information on a @@ -118,14 +118,22 @@ #define HID_FIELD_BUFFERED_BYTE 0x100 struct hiddev_usage_ref { - unsigned report_type; - unsigned report_id; - unsigned field_index; - unsigned usage_index; - unsigned usage_code; + __u32 report_type; + __u32 report_id; + __u32 field_index; + __u32 usage_index; + __u32 usage_code; __s32 value; }; +/* hiddev_usage_ref_multi is used for sending multiple bytes to a control. + * It really manifests itself as setting the value of consecutive usages */ +struct hiddev_usage_ref_multi { + struct hiddev_usage_ref uref; + __u32 num_values; + __s32 values[HID_MAX_USAGES]; +}; + /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has * been sent by the device @@ -160,6 +168,11 @@ #define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) #define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) +/* For writing/reading to multiple/consecutive usages */ +#define HIDIOCGUSAGES _IOWR('H', 0x12, struct hiddev_usage_ref_multi) +#define HIDIOCSUSAGES _IOW('H', 0x13, struct hiddev_usage_ref_multi) + + /* * Flags to be used in HIDIOCSFLAG */ @@ -204,6 +217,7 @@ void hiddev_disconnect(struct hid_device *); void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value); +void hiddev_report_event(struct hid_device *hid, struct hid_report *report); int __init hiddev_init(void); void __exit hiddev_exit(void); #else diff -urN linux-2.4.25/include/linux/ide.h linux-2.4.26/include/linux/ide.h --- linux-2.4.25/include/linux/ide.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/linux/ide.h 2004-04-14 06:05:40.000000000 -0700 @@ -1102,7 +1102,6 @@ #ifdef CONFIG_PROC_FS extern void proc_ide_create(void); extern void proc_ide_destroy(void); -extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_drives(ide_hwif_t *); extern void create_proc_ide_interfaces(void); diff -urN linux-2.4.25/include/linux/if_bonding.h linux-2.4.26/include/linux/if_bonding.h --- linux-2.4.25/include/linux/if_bonding.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/linux/if_bonding.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,7 +1,7 @@ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * - * + * * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes * NCM: Network and Communications Management, Inc. * @@ -10,11 +10,11 @@ * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. - * + * * 2003/03/18 - Amir Noam * - Added support for getting slave's speed and duplex via ethtool. * Needed for 802.3ad and other future modes. - * + * * 2003/03/18 - Tsippy Mendelson and * Shmulik Hen * - Enable support of modes that need to use the unique mac address of @@ -32,6 +32,9 @@ * 2003/05/01 - Amir Noam * - Added ABI version control to restore compatibility between * new/old ifenslave and new/old bonding. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes */ #ifndef _LINUX_IF_BONDING_H @@ -42,7 +45,7 @@ #include /* userland - kernel ABI version (2003/05/08) */ -#define BOND_ABI_VERSION 1 +#define BOND_ABI_VERSION 2 /* * We can remove these ioctl definitions in 2.5. People should use the @@ -77,10 +80,6 @@ #define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ -#define BOND_MULTICAST_DISABLED 0 -#define BOND_MULTICAST_ACTIVE 1 -#define BOND_MULTICAST_ALL 2 - typedef struct ifbond { __s32 bond_mode; __s32 num_slaves; @@ -91,8 +90,8 @@ { __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ char slave_name[IFNAMSIZ]; - char link; - char state; + __s8 link; + __s8 state; __u32 link_failure_count; } ifslave; @@ -115,3 +114,4 @@ * tab-width: 8 * End: */ + diff -urN linux-2.4.25/include/linux/if_vlan.h linux-2.4.26/include/linux/if_vlan.h --- linux-2.4.25/include/linux/if_vlan.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/if_vlan.h 2004-04-14 06:05:40.000000000 -0700 @@ -200,6 +200,148 @@ { return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1); } + +/** + * __vlan_put_tag - regular VLAN tag inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Inserts the VLAN tag into @skb as part of the payload + * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. + * + * Following the skb_unshare() example, in case of error, the calling function + * doesn't have to worry about freeing the original skb. + */ +static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_ethhdr *veth; + + if (skb_headroom(skb) < VLAN_HLEN) { + struct sk_buff *sk_tmp = skb; + skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); + kfree_skb(sk_tmp); + if (!skb) { + printk(KERN_ERR "vlan: failed to realloc headroom\n"); + return NULL; + } + } else { + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "vlan: failed to unshare skbuff\n"); + return NULL; + } + } + + veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); + + /* Move the mac addresses to the beginning of the new header. */ + memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN); + + /* first, the ethernet type */ + veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); + + /* now, the tag */ + veth->h_vlan_TCI = htons(tag); + + return skb; +} + +/** + * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Puts the VLAN tag in @skb->cb[] and lets the device do the rest + */ +static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + cookie->magic = VLAN_TX_COOKIE_MAGIC; + cookie->vlan_tag = tag; + + return skb; +} + +#define HAVE_VLAN_PUT_TAG + +/** + * vlan_put_tag - inserts VLAN tag according to device features + * @skb: skbuff to tag + * @tag: VLAN tag to insert + * + * Assumes skb->dev is the target that will xmit this frame. + * Returns a VLAN tagged skb. + */ +static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_put_tag(skb, tag); + } else { + return __vlan_put_tag(skb, tag); + } +} + +/** + * __vlan_get_tag - get the VLAN ID that is part of the payload + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not of VLAN type + */ +static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; + + if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { + return -EINVAL; + } + + *tag = ntohs(veth->h_vlan_TCI); + + return 0; +} + +/** + * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if @skb->cb[] is not set correctly + */ +static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + struct vlan_skb_tx_cookie *cookie; + + cookie = VLAN_TX_SKB_CB(skb); + if (cookie->magic == VLAN_TX_COOKIE_MAGIC) { + *tag = cookie->vlan_tag; + return 0; + } else { + *tag = 0; + return -EINVAL; + } +} + +#define HAVE_VLAN_GET_TAG + +/** + * vlan_get_tag - get the VLAN ID from the skb + * @skb: skbuff to query + * @tag: buffer to store vlaue + * + * Returns error if the skb is not VLAN tagged + */ +static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag) +{ + if (skb->dev->features & NETIF_F_HW_VLAN_TX) { + return __vlan_hwaccel_get_tag(skb, tag); + } else { + return __vlan_get_tag(skb, tag); + } +} + #endif /* __KERNEL__ */ /* VLAN IOCTLs are found in sockios.h */ diff -urN linux-2.4.25/include/linux/inetdevice.h linux-2.4.26/include/linux/inetdevice.h --- linux-2.4.25/include/linux/inetdevice.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/inetdevice.h 2004-04-14 06:05:40.000000000 -0700 @@ -18,6 +18,8 @@ int mc_forwarding; int tag; int arp_filter; + int arp_announce; + int arp_ignore; int medium_id; int force_igmp_version; void *sysctl; @@ -69,6 +71,8 @@ (ipv4_devconf.accept_redirects || (in_dev)->cnf.accept_redirects))) #define IN_DEV_ARPFILTER(in_dev) (ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter) +#define IN_DEV_ARP_ANNOUNCE(in_dev) (max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce)) +#define IN_DEV_ARP_IGNORE(in_dev) (max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore)) struct in_ifaddr { @@ -95,8 +99,9 @@ extern struct in_device *inetdev_init(struct net_device *dev); extern struct in_device *inetdev_by_index(int); extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope); +extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope); extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask); -extern void inet_forward_change(void); +extern void inet_forward_change(int); static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa) { diff -urN linux-2.4.25/include/linux/init.h linux-2.4.26/include/linux/init.h --- linux-2.4.25/include/linux/init.h 2001-12-21 09:42:03.000000000 -0800 +++ linux-2.4.26/include/linux/init.h 2004-04-14 06:05:40.000000000 -0700 @@ -2,6 +2,7 @@ #define _LINUX_INIT_H #include +#include /* These macros are used to mark some functions or * initialized data (doesn't apply to uninitialized data) @@ -51,7 +52,7 @@ extern initcall_t __initcall_start, __initcall_end; #define __initcall(fn) \ - static initcall_t __initcall_##fn __init_call = fn + static initcall_t __initcall_##fn __attribute_used__ __init_call = fn #define __exitcall(fn) \ static exitcall_t __exitcall_##fn __exit_call = fn @@ -67,7 +68,7 @@ #define __setup(str, fn) \ static char __setup_str_##fn[] __initdata = str; \ - static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn } + static struct kernel_param __setup_##fn __attribute_used__ __initsetup = { __setup_str_##fn, fn } #endif /* __ASSEMBLY__ */ @@ -76,12 +77,12 @@ * or exit time. */ #define __init __attribute__ ((__section__ (".text.init"))) -#define __exit __attribute__ ((unused, __section__(".text.exit"))) +#define __exit __attribute_used__ __attribute__ (( __section__(".text.exit"))) #define __initdata __attribute__ ((__section__ (".data.init"))) -#define __exitdata __attribute__ ((unused, __section__ (".data.exit"))) -#define __initsetup __attribute__ ((unused,__section__ (".setup.init"))) -#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) -#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) +#define __exitdata __attribute_used__ __attribute__ ((__section__ (".data.exit"))) +#define __initsetup __attribute_used__ __attribute__ ((__section__ (".setup.init"))) +#define __init_call __attribute_used__ __attribute__ ((__section__ (".initcall.init"))) +#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) /* For assembly routines */ #define __INIT .section ".text.init","ax" diff -urN linux-2.4.25/include/linux/jhash.h linux-2.4.26/include/linux/jhash.h --- linux-2.4.25/include/linux/jhash.h 2003-06-13 07:51:38.000000000 -0700 +++ linux-2.4.26/include/linux/jhash.h 2004-04-14 06:05:40.000000000 -0700 @@ -41,10 +41,10 @@ * of bytes. No alignment or length assumptions are made about * the input key. */ -static inline u32 jhash(void *key, u32 length, u32 initval) +static inline u32 jhash(const void *key, u32 length, u32 initval) { u32 a, b, c, len; - u8 *k = key; + const u8 *k = key; len = length; a = b = JHASH_GOLDEN_RATIO; diff -urN linux-2.4.25/include/linux/lockd/debug.h linux-2.4.26/include/linux/lockd/debug.h --- linux-2.4.25/include/linux/lockd/debug.h 2001-11-22 11:47:20.000000000 -0800 +++ linux-2.4.26/include/linux/lockd/debug.h 2004-04-14 06:05:40.000000000 -0700 @@ -49,4 +49,13 @@ #define NLMDBG_ALL 0x7fff +/* + * Support for printing NLM cookies in dprintk() + */ +#ifdef RPC_DEBUG +struct nlm_cookie; +/* Call this function with the BKL held (it uses a static buffer) */ +extern const char *nlmdbg_cookie2a(const struct nlm_cookie *); +#endif + #endif /* LINUX_LOCKD_DEBUG_H */ diff -urN linux-2.4.25/include/linux/lockd/lockd.h linux-2.4.26/include/linux/lockd/lockd.h --- linux-2.4.25/include/linux/lockd/lockd.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/linux/lockd/lockd.h 2004-04-14 06:05:40.000000000 -0700 @@ -164,7 +164,7 @@ unsigned long nlmsvc_retry_blocked(void); int nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, int action); -void nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status); +void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); /* * File handling for the server personality diff -urN linux-2.4.25/include/linux/lockd/xdr.h linux-2.4.26/include/linux/lockd/xdr.h --- linux-2.4.25/include/linux/lockd/xdr.h 2001-11-22 11:47:20.000000000 -0800 +++ linux-2.4.26/include/linux/lockd/xdr.h 2004-04-14 06:05:40.000000000 -0700 @@ -33,14 +33,15 @@ }; /* - * NLM cookies. Technically they can be 1K, Nobody uses over 8 bytes - * however. + * NLM cookies. Technically they can be 1K, Few people use over 8 bytes, + * FreeBSD uses 16, Apple Mac OS-X 10.3 uses 20. */ struct nlm_cookie { - unsigned char data[8]; unsigned int len; +#define NLM_MAXCOOKIELEN 32 + unsigned char data[NLM_MAXCOOKIELEN]; }; /* diff -urN linux-2.4.25/include/linux/module.h linux-2.4.26/include/linux/module.h --- linux-2.4.25/include/linux/module.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.26/include/linux/module.h 2004-04-14 06:05:40.000000000 -0700 @@ -254,9 +254,9 @@ */ #define MODULE_GENERIC_TABLE(gtype,name) \ static const unsigned long __module_##gtype##_size \ - __attribute__ ((unused)) = sizeof(struct gtype##_id); \ + __attribute_used__ = sizeof(struct gtype##_id); \ static const struct gtype##_id * __module_##gtype##_table \ - __attribute__ ((unused)) = name + __attribute_used__ = name /* * The following license idents are currently accepted as indicating free @@ -319,7 +319,7 @@ */ #define MODULE_GENERIC_TABLE(gtype,name) \ static const struct gtype##_id * __module_##gtype##_table \ - __attribute__ ((unused, __section__(".data.exit"))) = name + __attribute_used__ __attribute__ ((__section__(".data.exit"))) = name #ifndef __GENKSYMS__ diff -urN linux-2.4.25/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.26/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.4.25/include/linux/netfilter_ipv4/ip_conntrack.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/netfilter_ipv4/ip_conntrack.h 2004-04-14 06:05:40.000000000 -0700 @@ -156,7 +156,8 @@ union ip_conntrack_expect_help help; }; -#include +struct ip_conntrack_helper; + struct ip_conntrack { /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, diff -urN linux-2.4.25/include/linux/netfilter_ipv4/ip_nat.h linux-2.4.26/include/linux/netfilter_ipv4/ip_nat.h --- linux-2.4.25/include/linux/netfilter_ipv4/ip_nat.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.26/include/linux/netfilter_ipv4/ip_nat.h 2004-04-14 06:05:40.000000000 -0700 @@ -105,9 +105,6 @@ /* Manipulations to be done on this conntrack. */ struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS]; - /* The mapping type which created us (NULL for null mapping). */ - const struct ip_nat_mapping_type *mtype; - struct ip_nat_hash bysource, byipsproto; /* Helper (NULL if none). */ diff -urN linux-2.4.25/include/linux/netfilter_ipv4/listhelp.h linux-2.4.26/include/linux/netfilter_ipv4/listhelp.h --- linux-2.4.25/include/linux/netfilter_ipv4/listhelp.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/netfilter_ipv4/listhelp.h 2004-04-14 06:05:40.000000000 -0700 @@ -28,7 +28,7 @@ \ ASSERT_WRITE_LOCK(head); \ list_for_each(__i, (head)) \ - if (cmpfn((const type)__i , ## args)) { \ + if (cmpfn((type)__i , ## args)) { \ __j = __i; \ break; \ } \ diff -urN linux-2.4.25/include/linux/nfs_fs.h linux-2.4.26/include/linux/nfs_fs.h --- linux-2.4.25/include/linux/nfs_fs.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/linux/nfs_fs.h 2004-04-14 06:05:40.000000000 -0700 @@ -209,13 +209,13 @@ * Try to write back everything synchronously (but check the * return value!) */ -extern int nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int); -extern int nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int); +extern int nfs_sync_file(struct inode *, unsigned long, unsigned int, int); +extern int nfs_flush_file(struct inode *, unsigned long, unsigned int, int); extern int nfs_flush_list(struct list_head *, int, int); extern int nfs_scan_lru_dirty(struct nfs_server *, struct list_head *); extern int nfs_scan_lru_dirty_timeout(struct nfs_server *, struct list_head *); #ifdef CONFIG_NFS_V3 -extern int nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int); +extern int nfs_commit_file(struct inode *, int); extern int nfs_commit_list(struct list_head *, int); extern int nfs_scan_lru_commit(struct nfs_server *, struct list_head *); extern int nfs_scan_lru_commit_timeout(struct nfs_server *, struct list_head *); @@ -236,7 +236,7 @@ static inline int nfs_wb_all(struct inode *inode) { - int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT); + int error = nfs_sync_file(inode, 0, 0, FLUSH_WAIT); return (error < 0) ? error : 0; } @@ -246,17 +246,7 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) { - int error = nfs_sync_file(inode, 0, page_index(page), 1, FLUSH_WAIT | FLUSH_STABLE); - return (error < 0) ? error : 0; -} - -/* - * Write back all pending writes for one user.. - */ -static inline int -nfs_wb_file(struct inode *inode, struct file *file) -{ - int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT); + int error = nfs_sync_file(inode, page_index(page), 1, FLUSH_WAIT | FLUSH_STABLE); return (error < 0) ? error : 0; } diff -urN linux-2.4.25/include/linux/nfs_page.h linux-2.4.26/include/linux/nfs_page.h --- linux-2.4.25/include/linux/nfs_page.h 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.26/include/linux/nfs_page.h 2004-04-14 06:05:40.000000000 -0700 @@ -53,7 +53,7 @@ extern int nfs_scan_lru(struct list_head *, struct list_head *, int); extern int nfs_scan_lru_timeout(struct list_head *, struct list_head *, int); extern int nfs_scan_list(struct list_head *, struct list_head *, - struct file *, unsigned long, unsigned int); + unsigned long, unsigned int); extern int nfs_coalesce_requests(struct list_head *, struct list_head *, unsigned int); extern int nfs_wait_on_request(struct nfs_page *); diff -urN linux-2.4.25/include/linux/pci.h linux-2.4.26/include/linux/pci.h --- linux-2.4.25/include/linux/pci.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/linux/pci.h 2004-04-14 06:05:40.000000000 -0700 @@ -34,6 +34,7 @@ #define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ #define PCI_COMMAND_SERR 0x100 /* Enable SERR */ #define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ #define PCI_STATUS 0x06 /* 16 bits */ #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ diff -urN linux-2.4.25/include/linux/pci_ids.h linux-2.4.26/include/linux/pci_ids.h --- linux-2.4.25/include/linux/pci_ids.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/pci_ids.h 2004-04-14 06:05:40.000000000 -0700 @@ -287,6 +287,8 @@ #define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967 /* Radeon RV280 (9200) */ #define PCI_DEVICE_ID_ATI_RADEON_Y_ 0x5960 +#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961 +#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964 /* Radeon R300 (9700) */ #define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44 #define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45 @@ -315,6 +317,8 @@ #define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67 /* RadeonIGP */ #define PCI_DEVICE_ID_ATI_RADEON_IGP 0xCAB0 +/* ATI IXP Chipset */ +#define PCI_DEVICE_ID_ATI_IXP_IDE 0x4349 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -425,6 +429,7 @@ #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 +#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0 #define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 #define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 #define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C @@ -523,6 +528,7 @@ #define PCI_DEVICE_ID_SI_6202 0x0002 #define PCI_DEVICE_ID_SI_503 0x0008 #define PCI_DEVICE_ID_SI_ACPI 0x0009 +#define PCI_DEVICE_ID_SI_180 0x0180 #define PCI_DEVICE_ID_SI_5597_VGA 0x0200 #define PCI_DEVICE_ID_SI_6205 0x0205 #define PCI_DEVICE_ID_SI_501 0x0406 @@ -657,6 +663,8 @@ #define PCI_DEVICE_ID_TI_4410 0xac41 #define PCI_DEVICE_ID_TI_4451 0xac42 #define PCI_DEVICE_ID_TI_1420 0xac51 +#define PCI_DEVICE_ID_TI_1520 0xac55 +#define PCI_DEVICE_ID_TI_1510 0xac56 #define PCI_VENDOR_ID_SONY 0x104d #define PCI_DEVICE_ID_SONY_CXD3222 0x8039 @@ -750,6 +758,7 @@ #define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d #define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030 +#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 #define PCI_VENDOR_ID_YAMAHA 0x1073 #define PCI_DEVICE_ID_YAMAHA_724 0x0004 @@ -969,9 +978,15 @@ #define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C #define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 +#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 #define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 @@ -1677,6 +1692,12 @@ #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e #define PCI_DEVICE_ID_BCM4401 0x4401 +#define PCI_VENDOR_ID_ENE 0x1524 +#define PCI_DEVICE_ID_ENE_1211 0x1211 +#define PCI_DEVICE_ID_ENE_1225 0x1225 +#define PCI_DEVICE_ID_ENE_1410 0x1410 +#define PCI_DEVICE_ID_ENE_1420 0x1420 + #define PCI_VENDOR_ID_SYBA 0x1592 #define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 #define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 @@ -1853,7 +1874,7 @@ #define PCI_DEVICE_ID_INTEL_82801DB_7 0x24c7 #define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca #define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb -#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc +#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc #define PCI_DEVICE_ID_INTEL_82801DB_13 0x24cd #define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 #define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1 @@ -1880,6 +1901,10 @@ #define PCI_DEVICE_ID_INTEL_ESB_11 0x25ac #define PCI_DEVICE_ID_INTEL_ESB_12 0x25ad #define PCI_DEVICE_ID_INTEL_ESB_13 0x25ae +#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 +#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 +#define PCI_DEVICE_ID_INTEL_ICH6_2 0x266f +#define PCI_DEVICE_ID_INTEL_ICH6_3 0x266e #define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 #define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 #define PCI_DEVICE_ID_INTEL_80310 0x530d diff -urN linux-2.4.25/include/linux/pkt_sched.h linux-2.4.26/include/linux/pkt_sched.h --- linux-2.4.25/include/linux/pkt_sched.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/pkt_sched.h 2004-04-14 06:05:40.000000000 -0700 @@ -432,4 +432,11 @@ #define TCA_ATM_MAX TCA_ATM_STATE +/* Delay section */ +struct tc_dly_qopt +{ + __u32 latency; + __u32 limit; +}; + #endif diff -urN linux-2.4.25/include/linux/sctp.h linux-2.4.26/include/linux/sctp.h --- linux-2.4.25/include/linux/sctp.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/linux/sctp.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll @@ -42,6 +42,8 @@ * randall@sctp.chicago.il.us * kmorneau@cisco.com * qxie1@email.mot.com + * Sridhar Samudrala + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -59,14 +61,14 @@ __u16 dest; __u32 vtag; __u32 checksum; -} sctp_sctphdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_sctphdr_t; /* Section 3.2. Chunk Field Descriptions. */ typedef struct sctp_chunkhdr { __u8 type; __u8 flags; __u16 length; -} sctp_chunkhdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_chunkhdr_t; /* Section 3.2. Chunk Type Values. @@ -150,7 +152,7 @@ typedef struct sctp_paramhdr { __u16 type; __u16 length; -} sctp_paramhdr_t __attribute((packed)); +} __attribute__((packed)) sctp_paramhdr_t; typedef enum { @@ -200,12 +202,12 @@ __u16 ssn; __u32 ppid; __u8 payload[0]; -} sctp_datahdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_datahdr_t; typedef struct sctp_data_chunk { sctp_chunkhdr_t chunk_hdr; sctp_datahdr_t data_hdr; -} sctp_data_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_data_chunk_t; /* DATA Chuck Specific Flags */ enum { @@ -230,48 +232,48 @@ __u16 num_inbound_streams; __u32 initial_tsn; __u8 params[0]; -} sctp_inithdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_inithdr_t; typedef struct sctp_init_chunk { sctp_chunkhdr_t chunk_hdr; sctp_inithdr_t init_hdr; -} sctp_init_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_init_chunk_t; /* Section 3.3.2.1. IPv4 Address Parameter (5) */ typedef struct sctp_ipv4addr_param { sctp_paramhdr_t param_hdr; struct in_addr addr; -} sctp_ipv4addr_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_ipv4addr_param_t; /* Section 3.3.2.1. IPv6 Address Parameter (6) */ typedef struct sctp_ipv6addr_param { sctp_paramhdr_t param_hdr; struct in6_addr addr; -} sctp_ipv6addr_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_ipv6addr_param_t; /* Section 3.3.2.1 Cookie Preservative (9) */ typedef struct sctp_cookie_preserve_param { sctp_paramhdr_t param_hdr; uint32_t lifespan_increment; -} sctp_cookie_preserve_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_cookie_preserve_param_t; /* Section 3.3.2.1 Host Name Address (11) */ typedef struct sctp_hostname_param { sctp_paramhdr_t param_hdr; uint8_t hostname[0]; -} sctp_hostname_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_hostname_param_t; /* Section 3.3.2.1 Supported Address Types (12) */ typedef struct sctp_supported_addrs_param { sctp_paramhdr_t param_hdr; uint16_t types[0]; -} sctp_supported_addrs_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_supported_addrs_param_t; /* Appendix A. ECN Capable (32768) */ typedef struct sctp_ecn_capable_param { sctp_paramhdr_t param_hdr; -} sctp_ecn_capable_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_ecn_capable_param_t; @@ -285,13 +287,13 @@ typedef struct sctp_cookie_param { sctp_paramhdr_t p; __u8 body[0]; -} sctp_cookie_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_cookie_param_t; /* Section 3.3.3.1 Unrecognized Parameters (8) */ typedef struct sctp_unrecognized_param { sctp_paramhdr_t param_hdr; sctp_paramhdr_t unrecognized; -} sctp_unrecognized_param_t __attribute__((packed)); +} __attribute__((packed)) sctp_unrecognized_param_t; @@ -306,7 +308,7 @@ typedef struct sctp_gap_ack_block { __u16 start; __u16 end; -} sctp_gap_ack_block_t __attribute__((packed)); +} __attribute__((packed)) sctp_gap_ack_block_t; typedef uint32_t sctp_dup_tsn_t; @@ -321,12 +323,12 @@ __u16 num_gap_ack_blocks; __u16 num_dup_tsns; sctp_sack_variable_t variable[0]; -} sctp_sackhdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_sackhdr_t; typedef struct sctp_sack_chunk { sctp_chunkhdr_t chunk_hdr; sctp_sackhdr_t sack_hdr; -} sctp_sack_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_sack_chunk_t; /* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4): @@ -338,12 +340,12 @@ typedef struct sctp_heartbeathdr { sctp_paramhdr_t info; -} sctp_heartbeathdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_heartbeathdr_t; typedef struct sctp_heartbeat_chunk { sctp_chunkhdr_t chunk_hdr; sctp_heartbeathdr_t hb_hdr; -} sctp_heartbeat_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_heartbeat_chunk_t; /* For the abort and shutdown ACK we must carry the init tag in the @@ -352,7 +354,7 @@ */ typedef struct sctp_abort_chunk { sctp_chunkhdr_t uh; -} sctp_abort_chunkt_t __attribute__((packed)); +} __attribute__((packed)) sctp_abort_chunkt_t; /* For the graceful shutdown we must carry the tag (in common header) @@ -360,14 +362,12 @@ */ typedef struct sctp_shutdownhdr { __u32 cum_tsn_ack; -} sctp_shutdownhdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_shutdownhdr_t; struct sctp_shutdown_chunk_t { sctp_chunkhdr_t chunk_hdr; sctp_shutdownhdr_t shutdown_hdr; -} __attribute__((packed)); - - +} __attribute__ ((packed)); /* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ @@ -375,12 +375,12 @@ __u16 cause; __u16 length; __u8 variable[0]; -} sctp_errhdr_t __attribute__((packed)); +} __attribute__((packed)) sctp_errhdr_t; typedef struct sctp_operr_chunk { sctp_chunkhdr_t chunk_hdr; sctp_errhdr_t err_hdr; -} sctp_operr_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_operr_chunk_t; /* RFC 2960 3.3.10 - Operation Error * @@ -437,12 +437,13 @@ * 0x0101 Operation Refused Due to Resource Shortage. * 0x0102 Request to Delete Source IP Address. * 0x0103 Association Aborted due to illegal ASCONF-ACK + * 0x0104 Request refused - no authorization. */ SCTP_ERROR_DEL_LAST_IP = __constant_htons(0x0100), SCTP_ERROR_RSRC_LOW = __constant_htons(0x0101), SCTP_ERROR_DEL_SRC_IP = __constant_htons(0x0102), SCTP_ERROR_ASCONF_ACK = __constant_htons(0x0103), - + SCTP_ERROR_REQ_REFUSED = __constant_htons(0x0104) } sctp_error_t; @@ -457,7 +458,7 @@ typedef struct sctp_ecne_chunk { sctp_chunkhdr_t chunk_hdr; sctp_ecnehdr_t ence_hdr; -} sctp_ecne_chunk_t __attribute__((packed)); +} __attribute__((packed)) sctp_ecne_chunk_t; /* RFC 2960. Appendix A. Explicit Congestion Notification. * Congestion Window Reduced (CWR) (13) @@ -469,120 +470,57 @@ typedef struct sctp_cwr_chunk { sctp_chunkhdr_t chunk_hdr; sctp_cwrhdr_t cwr_hdr; -} sctp_cwr_chunk_t __attribute__((packed)); - - -/* FIXME: Cleanup needs to continue below this line. */ +} __attribute__((packed)) sctp_cwr_chunk_t; /* * ADDIP Section 3.1 New Chunk Types */ - -/* ADDIP Section 3.1.1 - * - * ASCONF-Request Correlation ID: 32 bits (unsigned integer) - * - * This is an opaque integer assigned by the sender to identify each - * request parameter. It is in host byte order and is only meaningful - * to the sender. The receiver of the ASCONF Chunk will copy this 32 - * bit value into the ASCONF Correlation ID field of the - * ASCONF-ACK. The sender of the ASCONF can use this same value in the - * ASCONF-ACK to find which request the response is for. - * - * ASCONF Parameter: TLV format - * - * Each Address configuration change is represented by a TLV parameter - * as defined in Section 3.2. One or more requests may be present in - * an ASCONF Chunk. - */ -typedef struct { - __u32 correlation; - sctp_paramhdr_t p; - __u8 payload[0]; -} sctpAsconfReq_t; - /* ADDIP - * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) + * Section 3.1.1 Address Configuration Change Chunk (ASCONF) * - * This chunk is used to communicate to the remote endpoint one of the - * configuration change requests that MUST be acknowledged. The - * information carried in the ASCONF Chunk uses the form of a - * Tag-Length-Value (TLV), as described in "3.2.1 - * Optional/Variable-length Parameter Format" in [RFC2960], for all - * variable parameters. - */ -typedef struct { - __u32 serial; - __u8 reserved[3]; - __u8 addr_type; - __u32 addr[4]; - sctpAsconfReq_t requests[0]; -} sctpAsconf_t; - -/* ADDIP - * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) - * - * ASCONF-Request Correlation ID: 32 bits (unsigned integer) - * - * This value is copied from the ASCONF Correlation ID received in the - * ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify - * which ASCONF parameter this response is associated with. - * - * ASCONF Parameter Response : TLV format - * - * The ASCONF Parameter Response is used in the ASCONF-ACK to report - * status of ASCONF processing. By default, if a responding endpoint - * does not include any Error Cause, a success is indicated. Thus a - * sender of an ASCONF-ACK MAY indicate complete success of all TLVs in - * an ASCONF by returning only the Chunk Type, Chunk Flags, Chunk Length - * (set to 8) and the Serial Number. - */ -typedef union { - struct { - __u32 correlation; - sctp_paramhdr_t header; /* success report */ - } success; - struct { - __u32 correlation; - sctp_paramhdr_t header; /* error cause indication */ - sctp_paramhdr_t errcause; - uint8_t request[0]; /* original request from ASCONF */ - } error; -#define __correlation success.correlation -#define __header success.header -#define __cause error.errcause -#define __request error.request -} sctpAsconfAckRsp_t; + * Serial Number: 32 bits (unsigned integer) + * This value represents a Serial Number for the ASCONF Chunk. The + * valid range of Serial Number is from 0 to 2^32-1. + * Serial Numbers wrap back to 0 after reaching 2^32 -1. + * + * Address Parameter: 8 or 20 bytes (depending on type) + * The address is an address of the sender of the ASCONF chunk, + * the address MUST be considered part of the association by the + * peer endpoint. This field may be used by the receiver of the + * ASCONF to help in finding the association. This parameter MUST + * be present in every ASCONF message i.e. it is a mandatory TLV + * parameter. + * + * ASCONF Parameter: TLV format + * Each Address configuration change is represented by a TLV + * parameter as defined in Section 3.2. One or more requests may + * be present in an ASCONF Chunk. + * + * Section 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK) + * + * Serial Number: 32 bits (unsigned integer) + * This value represents the Serial Number for the received ASCONF + * Chunk that is acknowledged by this chunk. This value is copied + * from the received ASCONF Chunk. + * + * ASCONF Parameter Response: TLV format + * The ASCONF Parameter Response is used in the ASCONF-ACK to + * report status of ASCONF processing. + */ +typedef struct sctp_addip_param { + sctp_paramhdr_t param_hdr; + __u32 crr_id; +} __attribute__((packed)) sctp_addip_param_t; -/* ADDIP - * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK) - * - * This chunk is used by the receiver of an ASCONF Chunk to - * acknowledge the reception. It carries zero or more results for any - * ASCONF Parameters that were processed by the receiver. - */ -typedef struct { +typedef struct sctp_addiphdr { __u32 serial; - sctpAsconfAckRsp_t responses[0]; -} sctpAsconfAck_t; + __u8 params[0]; +} __attribute__((packed)) sctp_addiphdr_t; -/********************************************************************* - * Internal structures - * - * These are data structures which never go out on the wire. - *********************************************************************/ - -/* What is this data structure for? The TLV isn't one--it is just a - * value. Perhaps this data structure ought to have a type--otherwise - * it is not unambigiously parseable. --piggy - */ -typedef struct { - struct list_head hook; - int length; /* length of the TLV */ - - /* the actually TLV to be copied into ASCONF_ACK */ - sctpAsconfAckRsp_t TLV; -} sctpAsconfAckRspNode_t; +typedef struct sctp_addip_chunk { + sctp_chunkhdr_t chunk_hdr; + sctp_addiphdr_t addip_hdr; +} __attribute__((packed)) sctp_addip_chunk_t; #endif /* __LINUX_SCTP_H__ */ diff -urN linux-2.4.25/include/linux/sisfb.h linux-2.4.26/include/linux/sisfb.h --- linux-2.4.25/include/linux/sisfb.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/sisfb.h 2004-04-14 06:05:40.000000000 -0700 @@ -38,7 +38,8 @@ #define TV_AVIDEO 0x00000100 #define TV_SVIDEO 0x00000200 #define TV_SCART 0x00000400 -#define VB_CONEXANT 0x00000800 +#define VB_CONEXANT 0x00000800 /* 661 series only */ +#define VB_TRUMPION VB_CONEXANT /* 300 series only */ #define TV_PALM 0x00001000 #define TV_PALN 0x00002000 #define TV_NTSCJ 0x00001000 @@ -71,7 +72,8 @@ #define TV_YPBPR525I TV_NTSC #define TV_YPBPR525P TV_PAL #define TV_YPBPR750P TV_PALM -#define TV_YPBPRALL (TV_YPBPR525I | TV_YPBPR525P | TV_YPBPR750P) +#define TV_YPBPR1080I TV_PALN +#define TV_YPBPRALL (TV_YPBPR525I | TV_YPBPR525P | TV_YPBPR750P | TV_YPBPR1080I) #define VB_SISBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV|VB_302ELV) #define VB_SISTVBRIDGE (VB_301|VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV) @@ -121,42 +123,44 @@ typedef struct _SISFB_INFO sisfb_info, *psisfb_info; struct _SISFB_INFO { - unsigned long sisfb_id; /* for identifying sisfb */ + u32 sisfb_id; /* for identifying sisfb */ #ifndef SISFB_ID #define SISFB_ID 0x53495346 /* Identify myself with 'SISF' */ #endif - int chip_id; /* PCI ID of detected chip */ - int memory; /* video memory in KB which sisfb manages */ - int heapstart; /* heap start (= sisfb "mem" argument) in KB */ - unsigned char fbvidmode; /* current sisfb mode */ + u32 chip_id; /* PCI ID of detected chip */ + u32 memory; /* video memory in KB which sisfb manages */ + u32 heapstart; /* heap start (= sisfb "mem" argument) in KB */ + u8 fbvidmode; /* current sisfb mode */ - unsigned char sisfb_version; - unsigned char sisfb_revision; - unsigned char sisfb_patchlevel; + u8 sisfb_version; + u8 sisfb_revision; + u8 sisfb_patchlevel; - unsigned char sisfb_caps; /* Sisfb capabilities */ + u8 sisfb_caps; /* Sisfb capabilities */ - int sisfb_tqlen; /* turbo queue length (in KB) */ + u32 sisfb_tqlen; /* turbo queue length (in KB) */ - unsigned int sisfb_pcibus; /* The card's PCI ID */ - unsigned int sisfb_pcislot; - unsigned int sisfb_pcifunc; + u32 sisfb_pcibus; /* The card's PCI ID */ + u32 sisfb_pcislot; + u32 sisfb_pcifunc; - unsigned char sisfb_lcdpdc; /* PanelDelayCompensation */ + u8 sisfb_lcdpdc; /* PanelDelayCompensation */ - unsigned char sisfb_lcda; /* Detected status of LCDA for low res/text modes */ + u8 sisfb_lcda; /* Detected status of LCDA for low res/text modes */ - unsigned long sisfb_vbflags; - unsigned long sisfb_currentvbflags; + u32 sisfb_vbflags; + u32 sisfb_currentvbflags; - int sisfb_scalelcd; - unsigned long sisfb_specialtiming; + u32 sisfb_scalelcd; + u32 sisfb_specialtiming; - unsigned char sisfb_haveemi; - unsigned char sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; - unsigned char sisfb_haveemilcd; + u8 sisfb_haveemi; + u8 sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33; + u8 sisfb_haveemilcd; - char reserved[213]; /* for future use */ + u8 sisfb_lcdpdca; /* PanelDelayCompensation for LCD-via-CRT1 */ + + u8 reserved[212]; /* for future use */ }; /* For fb memory manager */ @@ -221,62 +225,84 @@ } VGA_ENGINE; struct video_info { - int chip_id; - unsigned int video_size; - unsigned long video_base; - char * video_vbase; - unsigned long mmio_base; - char * mmio_vbase; - unsigned long vga_base; - unsigned long mtrr; - unsigned long heapstart; - - int video_bpp; - int video_cmap_len; - int video_width; - int video_height; - int video_vwidth; /* DEPRECATED - use var instead */ - int video_vheight; /* DEPRECATED - use var instead */ - int org_x; /* DEPRECATED - use var instead */ - int org_y; /* DEPRECATED - use var instead */ - int video_linelength; - unsigned int refresh_rate; - - unsigned long disp_state; /* DEPRECATED */ - unsigned char hasVB; /* DEPRECATED */ - unsigned char TV_type; /* DEPRECATED */ - unsigned char TV_plug; /* DEPRECATED */ + int chip_id; + unsigned int video_size; + unsigned long video_base; + char * video_vbase; + unsigned long mmio_size; + unsigned long mmio_base; + char * mmio_vbase; + unsigned long vga_base; + unsigned long mtrr; + unsigned long heapstart; + char * bios_vbase; + char * bios_abase; + + int video_bpp; + int video_cmap_len; + int video_width; + int video_height; + int video_vwidth; /* DEPRECATED - use var instead */ + int video_vheight; /* DEPRECATED - use var instead */ + int org_x; /* DEPRECATED - use var instead */ + int org_y; /* DEPRECATED - use var instead */ + int video_linelength; + unsigned int refresh_rate; + + unsigned long disp_state; /* DEPRECATED */ + unsigned char hasVB; /* DEPRECATED */ + unsigned char TV_type; /* DEPRECATED */ + unsigned char TV_plug; /* DEPRECATED */ SIS_CHIP_TYPE chip; unsigned char revision_id; - unsigned short DstColor; /* For 2d acceleration */ - unsigned long SiS310_AccelDepth; - unsigned long CommandReg; - - spinlock_t lockaccel; /* Do not use outside of kernel! */ - - unsigned int pcibus; - unsigned int pcislot; - unsigned int pcifunc; - - int accel; - - unsigned short subsysvendor; - unsigned short subsysdevice; - - unsigned long vbflags; /* Replacing deprecated stuff from above */ - unsigned long currentvbflags; - - int current_bpp; - int current_width; - int current_height; - int current_htotal; - int current_vtotal; - __u32 current_pixclock; - int current_refresh_rate; + unsigned short DstColor; /* For 2d acceleration */ + unsigned long SiS310_AccelDepth; + unsigned long CommandReg; + + spinlock_t lockaccel; /* Do not use outside of kernel! */ + + unsigned int pcibus; + unsigned int pcislot; + unsigned int pcifunc; + + int accel; + + unsigned short subsysvendor; + unsigned short subsysdevice; + + unsigned long vbflags; /* Replacing deprecated stuff from above */ + unsigned long currentvbflags; + + int current_bpp; + int current_width; + int current_height; + int current_htotal; + int current_vtotal; + __u32 current_pixclock; + int current_refresh_rate; + + u8 mode_no; + u8 rate_idx; + int modechanged; + unsigned char modeprechange; + + int newrom; + int registered; + + VGA_ENGINE sisvga_engine; + int hwcursor_size; + int CRT2_write_enable; + u8 caps; + + unsigned char detectedpdc; + unsigned char detectedpdca; + unsigned char detectedlcda; + + unsigned long hwcursor_vbase; - char reserved[200]; + char reserved[166]; }; extern struct video_info ivideo; diff -urN linux-2.4.25/include/linux/skbuff.h linux-2.4.26/include/linux/skbuff.h --- linux-2.4.25/include/linux/skbuff.h 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/include/linux/skbuff.h 2004-04-14 06:05:40.000000000 -0700 @@ -221,9 +221,6 @@ #endif }; -#define SK_WMEM_MAX 65535 -#define SK_RMEM_MAX 65535 - #ifdef __KERNEL__ /* * Handling routines are only of interest to the kernel diff -urN linux-2.4.25/include/linux/sysctl.h linux-2.4.26/include/linux/sysctl.h --- linux-2.4.25/include/linux/sysctl.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/sysctl.h 2004-04-14 06:05:40.000000000 -0700 @@ -312,6 +312,8 @@ NET_TCP_FRTO=92, NET_TCP_LOW_LATENCY=93, NET_IPV4_IPFRAG_SECRET_INTERVAL=94, + NET_TCP_WESTWOOD=95, + NET_IPV4_IGMP_MAX_MSF=96, }; enum { @@ -360,6 +362,8 @@ NET_IPV4_CONF_ARPFILTER=13, NET_IPV4_CONF_MEDIUM_ID=14, NET_IPV4_CONF_FORCE_IGMP_VERSION=17, + NET_IPV4_CONF_ARP_ANNOUNCE=18, + NET_IPV4_CONF_ARP_IGNORE=19, }; /* /proc/sys/net/ipv4/netfilter */ @@ -387,7 +391,8 @@ NET_IPV6_NEIGH=17, NET_IPV6_ROUTE=18, NET_IPV6_ICMP=19, - NET_IPV6_BINDV6ONLY=20 + NET_IPV6_BINDV6ONLY=20, + NET_IPV6_MLD_MAX_MSF=25, }; enum { @@ -548,6 +553,7 @@ NET_SCTP_HB_INTERVAL = 10, NET_SCTP_PRESERVE_ENABLE = 11, NET_SCTP_MAX_BURST = 12, + NET_SCTP_ADDIP_ENABLE = 13, }; /* /proc/sys/net/khttpd/ */ enum { diff -urN linux-2.4.25/include/linux/usb_gadget.h linux-2.4.26/include/linux/usb_gadget.h --- linux-2.4.25/include/linux/usb_gadget.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/linux/usb_gadget.h 2004-04-14 06:05:40.000000000 -0700 @@ -465,6 +465,8 @@ * driver setup() requests * @ep_list: List of other endpoints supported by the device. * @speed: Speed of current connection to USB host. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. * @name: Identifies the controller hardware type. Used in diagnostics * and sometimes configuration. * @dev: Driver model state for this abstract device. @@ -488,6 +490,7 @@ struct usb_ep *ep0; struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; + unsigned is_dualspeed:1; const char *name; struct __gadget_device { @@ -707,7 +710,7 @@ /** * struct usb_string - wraps a C string and its USB id * @id:the (nonzero) ID for this string - * @s:the string, in ISO-8859/1 characters + * @s:the string, in UTF-8 encoding * * If you're using usb_gadget_get_string(), use this to wrap a string * together with its ID. @@ -733,6 +736,17 @@ /* put descriptor for string with that id into buf (buflen >= 256) */ int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf); +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); #endif /* __KERNEL__ */ diff -urN linux-2.4.25/include/net/arp.h linux-2.4.26/include/net/arp.h --- linux-2.4.25/include/net/arp.h 2001-11-22 11:47:14.000000000 -0800 +++ linux-2.4.26/include/net/arp.h 2004-04-14 06:05:40.000000000 -0700 @@ -5,6 +5,8 @@ #include #include +#define HAVE_ARP_CREATE + extern struct neigh_table arp_tbl; extern void arp_init(void); @@ -19,6 +21,12 @@ extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); +extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw); +extern void arp_xmit(struct sk_buff *skb); + extern struct neigh_ops arp_broken_ops; #endif /* _ARP_H */ diff -urN linux-2.4.25/include/net/bluetooth/hci.h linux-2.4.26/include/net/bluetooth/hci.h --- linux-2.4.25/include/net/bluetooth/hci.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/net/bluetooth/hci.h 2004-04-14 06:05:40.000000000 -0700 @@ -50,6 +50,11 @@ #define HCI_RS232 4 #define HCI_PCI 5 +/* HCI device quirks */ +enum { + HCI_QUIRK_RESET_ON_INIT +}; + /* HCI device flags */ enum { HCI_UP, diff -urN linux-2.4.25/include/net/bluetooth/hci_core.h linux-2.4.26/include/net/bluetooth/hci_core.h --- linux-2.4.25/include/net/bluetooth/hci_core.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/net/bluetooth/hci_core.h 2004-04-14 06:05:40.000000000 -0700 @@ -72,7 +72,9 @@ __u16 pkt_type; __u16 link_policy; __u16 link_mode; - + + unsigned long quirks; + atomic_t cmd_cnt; unsigned int acl_cnt; unsigned int sco_cnt; diff -urN linux-2.4.25/include/net/ip_vs.h linux-2.4.26/include/net/ip_vs.h --- linux-2.4.25/include/net/ip_vs.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/ip_vs.h 2004-04-14 06:05:40.000000000 -0700 @@ -8,7 +8,7 @@ #include /* For __uXX types */ -#define IP_VS_VERSION_CODE 0x01000A +#define IP_VS_VERSION_CODE 0x01000B #define NVERSION(version) \ (version >> 16) & 0xFF, \ (version >> 8) & 0xFF, \ diff -urN linux-2.4.25/include/net/ipv6.h linux-2.4.26/include/net/ipv6.h --- linux-2.4.25/include/net/ipv6.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/ipv6.h 2004-04-14 06:05:40.000000000 -0700 @@ -104,6 +104,7 @@ /* sysctls */ extern int sysctl_ipv6_bindv6only; +extern int sysctl_mld_max_msf; extern struct ipv6_mib ipv6_statistics[NR_CPUS*2]; #define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field) @@ -320,7 +321,7 @@ struct ipv6_txoptions *opt, u8 *proto); -extern int ipv6_skip_exthdr(struct sk_buff *, int start, +extern int ipv6_skip_exthdr(const struct sk_buff *, int start, u8 *nexthdrp, int len); extern int ipv6_ext_hdr(u8 nexthdr); diff -urN linux-2.4.25/include/net/sctp/command.h linux-2.4.26/include/net/sctp/command.h --- linux-2.4.25/include/net/sctp/command.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/command.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,6 @@ -/* SCTP kernel reference Implementation Copyright (C) 1999-2001 - * Cisco, Motorola, and IBM +/* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 + * Copyright (C) 1999-2001 Cisco, Motorola * * This file is part of the SCTP kernel reference Implementation * @@ -87,6 +88,8 @@ SCTP_CMD_RTO_PENDING, /* Set transport's rto_pending. */ SCTP_CMD_PART_DELIVER, /* Partial data delivery considerations. */ SCTP_CMD_RENEGE, /* Renege data on an association. */ + SCTP_CMD_SETUP_T4, /* ADDIP, setup T4 RTO timer parms. */ + SCTP_CMD_PROCESS_OPERR, /* Process an ERROR chunk. */ SCTP_CMD_LAST } sctp_verb_t; diff -urN linux-2.4.25/include/net/sctp/compat.h linux-2.4.26/include/net/sctp/compat.h --- linux-2.4.25/include/net/sctp/compat.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/compat.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,6 @@ /* SCTP kernel reference Implementation * + * (C) Copyright IBM Corp. 2004 * Copyright (c) 2003 Hewlett-Packard Company * * This file is part of the SCTP kernel reference Implementation @@ -36,7 +37,7 @@ #include /* - * The following defines are for compatibility with 2.5 + * The following defines are for compatibility with 2.6 */ /* * container_of - cast a member of a structure out to the containing structure @@ -54,7 +55,6 @@ extern type name[] #define SNMP_DEC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_softirq()].field--) -#define sctp_sk(__sk) (&(((struct sock *)__sk)->tp_pinfo.af_sctp)) #define inet_sk(__sk) (&(((struct sock *)__sk)->protinfo.af_inet)) #define inet6_sk(__sk) (&(((struct sock *)__sk)->net_pinfo.af_inet6)) @@ -64,9 +64,37 @@ #define __unsafe(x) MOD_INC_USE_COUNT #define dst_pmtu(x) ((x)->pmtu) -void sctp_hash_digest(const char *key, const int in_key_len, - const char *text, const int text_len, - __u8 *digest); +#define sk_family family +#define sk_state state +#define sk_type type +#define sk_socket socket +#define sk_prot prot +#define sk_rcvbuf rcvbuf +#define sk_sndbuf sndbuf +#define sk_ack_backlog ack_backlog +#define sk_max_ack_backlog max_ack_backlog +#define sk_write_space write_space +#define sk_use_write_queue use_write_queue +#define sk_err err +#define sk_err_soft err_soft +#define sk_error_report error_report +#define sk_error_queue error_queue +#define sk_shutdown shutdown +#define sk_state_change state_change +#define sk_receive_queue receive_queue +#define sk_data_ready data_ready +#define sk_no_check no_check +#define sk_reuse reuse +#define sk_destruct destruct +#define sk_zapped zapped +#define sk_protocol protocol +#define sk_backlog_rcv backlog_rcv +#define sk_allocation allocation +#define sk_lingertime lingertime +#define sk_sleep sleep +#define sk_wmem_queued wmem_queued +#define sk_bound_dev_if bound_dev_if + /* * find last bit set. */ diff -urN linux-2.4.25/include/net/sctp/constants.h linux-2.4.26/include/net/sctp/constants.h --- linux-2.4.25/include/net/sctp/constants.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/constants.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -75,6 +75,7 @@ #define SCTP_NUM_BASE_CHUNK_TYPES (SCTP_CID_BASE_MAX + 1) #define SCTP_NUM_CHUNK_TYPES (SCTP_NUM_BASE_CHUNKTYPES + 2) +#define SCTP_NUM_ADDIP_CHUNK_TYPES 2 /* These are the different flavours of event. */ typedef enum { @@ -99,6 +100,7 @@ SCTP_EVENT_TIMEOUT_T1_INIT, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, SCTP_EVENT_TIMEOUT_T3_RTX, + SCTP_EVENT_TIMEOUT_T4_RTO, SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, SCTP_EVENT_TIMEOUT_HEARTBEAT, SCTP_EVENT_TIMEOUT_SACK, @@ -122,9 +124,10 @@ SCTP_PRIMITIVE_ABORT, SCTP_PRIMITIVE_SEND, SCTP_PRIMITIVE_REQUESTHEARTBEAT, + SCTP_PRIMITIVE_ASCONF, } sctp_event_primitive_t; -#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_REQUESTHEARTBEAT +#define SCTP_EVENT_PRIMITIVE_MAX SCTP_PRIMITIVE_ASCONF #define SCTP_NUM_PRIMITIVE_TYPES (SCTP_EVENT_PRIMITIVE_MAX + 1) /* We define here a utility type for manipulating subtypes. @@ -267,7 +270,8 @@ * nearest power of 2. */ enum { SCTP_MIN_PMTU = 576 }; -enum { SCTP_MAX_DUP_TSNS = 128 }; +enum { SCTP_MAX_DUP_TSNS = 16 }; +enum { SCTP_MAX_GABS = 16 }; typedef enum { SCTP_COUNTER_INIT_ERROR, @@ -319,7 +323,7 @@ #define SCTP_DEFAULT_COOKIE_LIFE_USEC 0 /* microseconds */ #define SCTP_DEFAULT_MINWINDOW 1500 /* default minimum rwnd size */ -#define SCTP_DEFAULT_MAXWINDOW 32768 /* default rwnd size */ +#define SCTP_DEFAULT_MAXWINDOW 65535 /* default rwnd size */ #define SCTP_DEFAULT_MAXSEGMENT 1500 /* MTU size, this is the limit * to which we will raise the P-MTU. */ diff -urN linux-2.4.25/include/net/sctp/sctp.h linux-2.4.26/include/net/sctp/sctp.h --- linux-2.4.25/include/net/sctp/sctp.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/net/sctp/sctp.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001-2003 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -39,6 +39,8 @@ * Daisy Chang * Sridhar Samudrala * Ardelle Fan + * Ryan Layer + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -75,7 +77,6 @@ #include #include #include -#include #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #include @@ -114,17 +115,20 @@ #define SCTP_STATIC static #endif +#define SCTP_MSECS_TO_JIFFIES(msec) \ + (((msec / 1000) * HZ) + ((msec % 1000) * HZ) / 1000) +#define JIFFIES_TO_MSECS(jiff) \ + (((jiff / HZ) * 1000) + ((jiff % HZ) * 1000) / HZ) + /* * Function declarations. */ /* - * sctp_protocol.c + * sctp/protocol.c */ -extern struct sctp_protocol sctp_proto; extern struct sock *sctp_get_ctl_sock(void); -extern int sctp_copy_local_addr_list(struct sctp_protocol *, - struct sctp_bind_addr *, +extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, sctp_scope_t, int gfp, int flags); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern int sctp_register_pf(struct sctp_pf *, sa_family_t); @@ -132,54 +136,55 @@ /* * sctp/socket.c */ -extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); -extern int sctp_inet_listen(struct socket *sock, int backlog); -extern void sctp_write_space(struct sock *sk); -extern unsigned int sctp_poll(struct file *file, struct socket *sock, +int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb); +int sctp_inet_listen(struct socket *sock, int backlog); +void sctp_write_space(struct sock *sk); +unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); /* * sctp/primitive.c */ -extern int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg); -extern int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); -extern int sctp_primitive_ABORT(struct sctp_association *, void *arg); -extern int sctp_primitive_SEND(struct sctp_association *, void *arg); -extern int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg); +int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg); +int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); +int sctp_primitive_ABORT(struct sctp_association *, void *arg); +int sctp_primitive_SEND(struct sctp_association *, void *arg); +int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg); +int sctp_primitive_ASCONF(struct sctp_association *, void *arg); /* * sctp/crc32c.c */ -extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count); -extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); -extern __u32 sctp_end_cksum(__u32 cksum); -extern __u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum); +__u32 sctp_start_cksum(__u8 *ptr, __u16 count); +__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum); +__u32 sctp_end_cksum(__u32 cksum); +__u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum); /* * sctp/input.c */ -extern int sctp_rcv(struct sk_buff *skb); -extern void sctp_v4_err(struct sk_buff *skb, u32 info); -extern void sctp_hash_established(struct sctp_association *); -extern void __sctp_hash_established(struct sctp_association *); -extern void sctp_unhash_established(struct sctp_association *); -extern void __sctp_unhash_established(struct sctp_association *); -extern void sctp_hash_endpoint(struct sctp_endpoint *); -extern void __sctp_hash_endpoint(struct sctp_endpoint *); -extern void sctp_unhash_endpoint(struct sctp_endpoint *); -extern void __sctp_unhash_endpoint(struct sctp_endpoint *); -extern struct sctp_association *__sctp_lookup_association( +int sctp_rcv(struct sk_buff *skb); +void sctp_v4_err(struct sk_buff *skb, u32 info); +void sctp_hash_established(struct sctp_association *); +void __sctp_hash_established(struct sctp_association *); +void sctp_unhash_established(struct sctp_association *); +void __sctp_unhash_established(struct sctp_association *); +void sctp_hash_endpoint(struct sctp_endpoint *); +void __sctp_hash_endpoint(struct sctp_endpoint *); +void sctp_unhash_endpoint(struct sctp_endpoint *); +void __sctp_unhash_endpoint(struct sctp_endpoint *); +struct sctp_association *__sctp_lookup_association( const union sctp_addr *, const union sctp_addr *, struct sctp_transport **); -extern struct sock *sctp_err_lookup(int family, struct sk_buff *, - struct sctphdr *, struct sctp_endpoint **, - struct sctp_association **, - struct sctp_transport **); -extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, +struct sock *sctp_err_lookup(int family, struct sk_buff *, + struct sctphdr *, struct sctp_endpoint **, + struct sctp_association **, + struct sctp_transport **); +void sctp_err_finish(struct sock *, struct sctp_endpoint *, struct sctp_association *); -extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, - struct sctp_transport *t, __u32 pmtu); +void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, + struct sctp_transport *t, __u32 pmtu); /* * Section: Macros, externs, and inlines @@ -227,10 +232,10 @@ if (addr < PAGE_OFFSET) return 0; - page = virt_to_page((void*)addr); + page = virt_to_page(addr); /* Is this page valid? */ - if (!virt_addr_valid((void*)addr) || PageReserved(page)) + if (!virt_addr_valid(addr) || PageReserved(page)) return 0; return 1; @@ -277,6 +282,7 @@ extern atomic_t sctp_dbg_objcnt_bind_addr; extern atomic_t sctp_dbg_objcnt_addr; extern atomic_t sctp_dbg_objcnt_ssnmap; +extern atomic_t sctp_dbg_objcnt_datamsg; /* Macros to atomically increment/decrement objcnt counters. */ #define SCTP_DBG_OBJCNT_INC(name) \ @@ -292,8 +298,8 @@ #define SCTP_DBG_OBJCNT_ENTRY(name) \ {.label= #name, .counter= &sctp_dbg_objcnt_## name} -extern void sctp_dbg_objcnt_init(void); -extern void sctp_dbg_objcnt_exit(void); +void sctp_dbg_objcnt_init(void); +void sctp_dbg_objcnt_exit(void); #else @@ -306,11 +312,17 @@ #endif /* CONFIG_SCTP_DBG_OBJCOUNT */ #if defined CONFIG_SYSCTL -extern void sctp_sysctl_register(void); -extern void sctp_sysctl_unregister(void); +void sctp_sysctl_register(void); +void sctp_sysctl_unregister(void); #else static inline void sctp_sysctl_register(void) { return; } static inline void sctp_sysctl_unregister(void) { return; } +static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, void *newval, + size_t newlen, void **context) +{ + return -ENOSYS; +} #endif /* Size of Supported Address Parameter for 'x' address types. */ @@ -318,9 +330,9 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -extern int sctp_v6_init(void); -extern void sctp_v6_exit(void); -extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, +int sctp_v6_init(void); +void sctp_v6_exit(void); +void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __u32 info); #else /* #ifdef defined(CONFIG_IPV6) */ @@ -348,7 +360,6 @@ return (sctp_assoc_t) asoc; } - /* Look up the association by its id. */ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); @@ -399,6 +410,12 @@ return result; } +/* Tests if the list has one and only one entry. */ +static inline int sctp_list_single_entry(struct list_head *head) +{ + return ((head->next != head) && (head->next == head->prev)); +} + /* Calculate the size (in bytes) occupied by the data of an iovec. */ static inline size_t get_user_iov_size(struct iovec *iov, int iovlen) { @@ -418,6 +435,10 @@ static __u32 sctp_rand; __s32 ret; + /* Avoid divide by zero. */ + if (!rto) + rto = 1; + sctp_rand += jiffies; sctp_rand ^= (sctp_rand << 12); sctp_rand ^= (sctp_rand >> 20); @@ -430,12 +451,16 @@ } /* Break down data chunks at this point. */ -static inline int sctp_frag_point(int pmtu) +static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu) { - pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); - pmtu -= sizeof(struct sctp_sack_chunk); + int frag = pmtu; + frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk); + frag -= sizeof(struct sctp_sack_chunk); + + if (sp->user_frag) + frag = min_t(int, frag, sp->user_frag); - return pmtu; + return frag; } /* Walk through a list of TLV parameters. Don't trust the @@ -444,7 +469,7 @@ * there is room for a param header too. */ #define sctp_walk_params(pos, chunk, member)\ -_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) +_sctp_walk_params((pos), (chunk), WORD_ROUND(ntohs((chunk)->chunk_hdr.length)), member) #define _sctp_walk_params(pos, chunk, end, member)\ for (pos.v = chunk->member;\ @@ -452,6 +477,18 @@ pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \ pos.v += WORD_ROUND(ntohs(pos.p->length))) +#define sctp_walk_errors(err, chunk_hdr)\ +_sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length)) + +#define _sctp_walk_errors(err, chunk_hdr, end)\ +for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ + sizeof(sctp_chunkhdr_t));\ + (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\ + (void *)err <= (void *)chunk_hdr + end - \ + WORD_ROUND(ntohs(err->length));\ + err = (sctp_errhdr_t *)((void *)err + \ + WORD_ROUND(ntohs(err->length)))) + /* Round an int up to the next multiple of 4. */ #define WORD_ROUND(s) (((s)+3)&~3) @@ -462,37 +499,28 @@ #define tv_lt(s, t) \ (s.tv_sec < t.tv_sec || (s.tv_sec == t.tv_sec && s.tv_usec < t.tv_usec)) -/* Stolen from net/profile.h. Using it from there is more grief than - * it is worth. - */ -static inline void tv_add(const struct timeval *entered, struct timeval *leaved) -{ - time_t usecs = leaved->tv_usec + entered->tv_usec; - time_t secs = leaved->tv_sec + entered->tv_sec; - - if (usecs >= 1000000) { - usecs -= 1000000; - secs++; - } - leaved->tv_sec = secs; - leaved->tv_usec = usecs; -} - +/* Add tv1 to tv2. */ +#define TIMEVAL_ADD(tv1, tv2) \ +({ \ + suseconds_t usecs = (tv2).tv_usec + (tv1).tv_usec; \ + time_t secs = (tv2).tv_sec + (tv1).tv_sec; \ +\ + if (usecs >= 1000000) { \ + usecs -= 1000000; \ + secs++; \ + } \ + (tv2).tv_sec = secs; \ + (tv2).tv_usec = usecs; \ +}) /* External references. */ extern struct proto sctp_prot; extern struct proc_dir_entry *proc_net_sctp; -extern void sctp_put_port(struct sock *sk); +void sctp_put_port(struct sock *sk); /* Static inline functions. */ -/* Return the SCTP protocol structure. */ -static inline struct sctp_protocol *sctp_get_protocol(void) -{ - return &sctp_proto; -} - /* Convert from an IP version number to an Address Family symbol. */ static inline int ipver2af(__u8 ipver) { @@ -506,6 +534,19 @@ }; } +/* Convert from an address parameter type to an address family. */ +static inline int param_type2af(__u16 type) +{ + switch (type) { + case SCTP_PARAM_IPV4_ADDRESS: + return AF_INET; + case SCTP_PARAM_IPV6_ADDRESS: + return AF_INET6; + default: + return 0; + }; +} + /* Perform some sanity checks. */ static inline int sctp_sanity_check(void) { @@ -520,24 +561,21 @@ /* This is the hash function for the SCTP port hash table. */ static inline int sctp_phashfn(__u16 lport) { - struct sctp_protocol *sctp_proto = sctp_get_protocol(); - return (lport & (sctp_proto->port_hashsize - 1)); + return (lport & (sctp_port_hashsize - 1)); } /* This is the hash function for the endpoint hash table. */ static inline int sctp_ep_hashfn(__u16 lport) { - struct sctp_protocol *sctp_proto = sctp_get_protocol(); - return (lport & (sctp_proto->ep_hashsize - 1)); + return (lport & (sctp_ep_hashsize - 1)); } /* This is the hash function for the association hash table. */ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) { - struct sctp_protocol *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= h>>8; - return (h & (sctp_proto->assoc_hashsize - 1)); + return (h & (sctp_assoc_hashsize - 1)); } /* This is the hash function for the association hash table. This is @@ -546,10 +584,53 @@ */ static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) { - struct sctp_protocol *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= vtag; - return (h & (sctp_proto->assoc_hashsize-1)); + return (h & (sctp_assoc_hashsize-1)); +} + +#define sctp_sk(__sk) (&(((struct sock *)__sk)->tp_pinfo.af_sctp)) +#define sctp_opt2sk(__sp) container_of(__sp, struct sock, tp_pinfo.af_sctp) + +/* Is a socket of this style? */ +#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) +int static inline __sctp_style(const struct sock *sk, sctp_socket_type_t style) +{ + return sctp_sk(sk)->type == style; +} + +/* Is the association in this state? */ +#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state)) +int static inline __sctp_state(const struct sctp_association *asoc, + sctp_state_t state) +{ + return asoc->state == state; +} + +/* Is the socket in this state? */ +#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) +int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) +{ + return sk->sk_state == state; +} + +/* Map v4-mapped v6 address back to v4 address */ +static inline void sctp_v6_map_v4(union sctp_addr *addr) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = addr->v6.sin6_port; + addr->v4.sin_addr.s_addr = addr->v6.sin6_addr.s6_addr32[3]; +} + +/* Map v4 address to v4-mapped v6 address */ +static inline void sctp_v4_map_v6(union sctp_addr *addr) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = addr->v4.sin_port; + addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + addr->v6.sin6_addr.s6_addr32[0] = 0; + addr->v6.sin6_addr.s6_addr32[1] = 0; + addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); } #endif /* __net_sctp_h__ */ diff -urN linux-2.4.25/include/net/sctp/sm.h linux-2.4.26/include/net/sctp/sm.h --- linux-2.4.25/include/net/sctp/sm.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/sm.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,15 +1,11 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * - * This file is part of the implementation of the add-IP extension, - * based on June 29, 2001, - * for the SCTP kernel reference Implementation. - * * These are definitions needed by the state machine. * * The SCTP reference implementation is free software; @@ -45,12 +41,12 @@ * Sridhar Samudrala * Daisy Chang * Ardelle Fan + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ - #include #include #include @@ -89,7 +85,7 @@ typedef void (sctp_timer_event_t) (unsigned long); typedef struct { sctp_state_fn_t *fn; - char *name; + const char *name; } sctp_sm_table_entry_t; /* A naming convention of "sctp_sf_xxx" applies to all the state functions @@ -122,6 +118,7 @@ sctp_state_fn_t sctp_sf_operr_notify; sctp_state_fn_t sctp_sf_t1_timer_expire; sctp_state_fn_t sctp_sf_t2_timer_expire; +sctp_state_fn_t sctp_sf_t4_timer_expire; sctp_state_fn_t sctp_sf_t5_timer_expire; sctp_state_fn_t sctp_sf_sendbeat_8_3; sctp_state_fn_t sctp_sf_beat_8_3; @@ -142,6 +139,8 @@ sctp_state_fn_t sctp_sf_do_8_5_1_E_sa; sctp_state_fn_t sctp_sf_cookie_echoed_err; sctp_state_fn_t sctp_sf_do_5_2_6_stale; +sctp_state_fn_t sctp_sf_do_asconf; +sctp_state_fn_t sctp_sf_do_asconf_ack; /* Prototypes for primitive event state functions. */ sctp_state_fn_t sctp_sf_do_prm_asoc; @@ -159,6 +158,7 @@ sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_ignore_primitive; sctp_state_fn_t sctp_sf_do_prm_requestheartbeat; +sctp_state_fn_t sctp_sf_do_prm_asconf; /* Prototypes for other event state functions. */ sctp_state_fn_t sctp_sf_do_9_2_start_shutdown; @@ -181,9 +181,6 @@ sctp_state_fn_t sctp_sf_do_9_2_reshut; sctp_state_fn_t sctp_sf_do_9_2_shutack; -sctp_state_fn_t lucky; -sctp_state_fn_t other_stupid; - /* Prototypes for timeout event state functions. Not in use. */ sctp_state_fn_t sctp_do_4_2_reinit; sctp_state_fn_t sctp_do_4_3_reecho; @@ -192,15 +189,11 @@ sctp_state_fn_t sctp_do_8_3_hb_err; sctp_state_fn_t sctp_heartoff; -/* Prototypes for addip related state functions. Not in use. */ -sctp_state_fn_t sctp_addip_do_asconf; -sctp_state_fn_t sctp_addip_do_asconf_ack; - /* Prototypes for utility support functions. */ __u8 sctp_get_chunk_type(struct sctp_chunk *chunk); -sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, - sctp_state_t state, - sctp_subtype_t event_subtype); +const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t, + sctp_state_t, + sctp_subtype_t); int sctp_chunk_iif(const struct sctp_chunk *); struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *, struct sctp_chunk *, @@ -209,71 +202,84 @@ void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag); /* Prototypes for chunk-building functions. */ -sctp_chunk_t *sctp_make_init(const struct sctp_association *, - const sctp_bind_addr_t *, +struct sctp_chunk *sctp_make_init(const struct sctp_association *, + const struct sctp_bind_addr *, int gfp, int vparam_len); -sctp_chunk_t *sctp_make_init_ack(const struct sctp_association *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *, + const struct sctp_chunk *, const int gfp, const int unkparam_len); -sctp_chunk_t *sctp_make_cookie_echo(const struct sctp_association *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cookie_ack(const struct sctp_association *, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_cwr(const struct sctp_association *, +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *, const __u32 lowest_tsn, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_datafrag(struct sctp_association *, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data, __u8 flags, __u16 ssn); -sctp_chunk_t * sctp_make_datafrag_empty(struct sctp_association *, +struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 flags, __u16 ssn); -sctp_chunk_t *sctp_make_data(struct sctp_association *, +struct sctp_chunk *sctp_make_data(struct sctp_association *, const struct sctp_sndrcvinfo *sinfo, int len, const __u8 *data); -sctp_chunk_t *sctp_make_data_empty(struct sctp_association *, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *, const struct sctp_sndrcvinfo *, int len); -sctp_chunk_t *sctp_make_ecne(const struct sctp_association *, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, const __u32); -sctp_chunk_t *sctp_make_sack(const struct sctp_association *); -sctp_chunk_t *sctp_make_shutdown(const struct sctp_association *asoc); -sctp_chunk_t *sctp_make_shutdown_ack(const struct sctp_association *asoc, - const sctp_chunk_t *); -sctp_chunk_t *sctp_make_shutdown_complete(const struct sctp_association *, - const sctp_chunk_t *); -void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t); -sctp_chunk_t *sctp_make_abort(const struct sctp_association *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_sack(const struct sctp_association *); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk); +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *); +struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, + const struct sctp_chunk *); +void sctp_init_cause(struct sctp_chunk *, __u16 cause, const void *, size_t); +struct sctp_chunk *sctp_make_abort(const struct sctp_association *, + const struct sctp_chunk *, const size_t hint); -sctp_chunk_t *sctp_make_abort_no_data(const struct sctp_association *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *, + const struct sctp_chunk *, __u32 tsn); -sctp_chunk_t *sctp_make_abort_user(const struct sctp_association *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *, + const struct sctp_chunk *, const struct msghdr *); -sctp_chunk_t *sctp_make_heartbeat(const struct sctp_association *, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *, const struct sctp_transport *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_heartbeat_ack(const struct sctp_association *, - const sctp_chunk_t *, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *, + const struct sctp_chunk *, const void *payload, const size_t paylen); -sctp_chunk_t *sctp_make_op_error(const struct sctp_association *, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen); -void sctp_chunk_assign_tsn(sctp_chunk_t *); -void sctp_chunk_assign_ssn(sctp_chunk_t *); -int sctp_datachunks_from_user(struct sctp_association *, - const struct sctp_sndrcvinfo *, - struct msghdr *, int len, - struct sk_buff_head *); +struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, + union sctp_addr *addr, + int vparam_len); +struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, + union sctp_addr *, + struct sockaddr *, + int, __u16); +struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, + union sctp_addr *addr); +struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc, + __u32 serial, int vparam_len); +struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + struct sctp_chunk *asconf); +int sctp_process_asconf_ack(struct sctp_association *asoc, + struct sctp_chunk *asconf_ack); + +void sctp_chunk_assign_tsn(struct sctp_chunk *); +void sctp_chunk_assign_ssn(struct sctp_chunk *); /* Prototypes for statetable processing. */ @@ -294,24 +300,17 @@ int gfp); /* 2nd level prototypes */ -int -sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, - sctp_state_t state, - struct sctp_endpoint *ep, - struct sctp_association *asoc, - void *event_arg, - sctp_disposition_t status, - sctp_cmd_seq_t *retval, - int gfp); +int sctp_cmd_interpreter(sctp_event_t, sctp_subtype_t, sctp_state_t, + struct sctp_endpoint *, struct sctp_association *, + void *event_arg, sctp_disposition_t, + sctp_cmd_seq_t *retval, int gfp); int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *); -void sctp_do_TSNdup(struct sctp_association *, sctp_chunk_t *, long gap); - void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer); -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); +sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *); struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *, const struct sctp_association *, struct sctp_chunk *chunk, @@ -321,39 +320,33 @@ const struct sctp_chunk *); void sctp_ootb_pkt_free(struct sctp_packet *); -sctp_cookie_param_t * +struct sctp_cookie_param * sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *, const struct sctp_chunk *, int *cookie_len, const __u8 *, int addrs_len); struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *, const struct sctp_association *, - sctp_chunk_t *, int gfp, int *err, - sctp_chunk_t **err_chk_p); + struct sctp_chunk *, int gfp, int *err, + struct sctp_chunk **err_chk_p); int sctp_addip_addr_config(struct sctp_association *, sctp_param_t, struct sockaddr_storage*, int); void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - const sctp_chunk_t *chunk, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk); + struct sctp_chunk *err_chunk); /* 3rd level prototypes */ __u32 sctp_generate_tag(const struct sctp_endpoint *); __u32 sctp_generate_tsn(const struct sctp_endpoint *); -/* 4th level prototypes */ -void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *, - __u16 port, int iif); -int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *); -int sockaddr2sctp_addr(const union sctp_addr *, sctp_addr_param_t *); - /* Extern declarations for major data structures. */ -sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); -extern sctp_sm_table_entry_t +const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); +extern const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES]; -extern sctp_sm_table_entry_t +extern const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES]; -extern sctp_sm_table_entry_t +extern const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES]; extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES]; @@ -361,7 +354,7 @@ /* Get the size of a DATA chunk payload. */ -static inline __u16 sctp_data_size(sctp_chunk_t *chunk) +static inline __u16 sctp_data_size(struct sctp_chunk *chunk) { __u16 size; @@ -438,6 +431,21 @@ return (((s) == (t)) || (((s) - (t)) & SSN_SIGN_BIT)); } +/* + * ADDIP 3.1.1 + * The valid range of Serial Number is from 0 to 4294967295 (2**32 - 1). Serial + * Numbers wrap back to 0 after reaching 4294967295. + */ +enum { + ADDIP_SERIAL_SIGN_BIT = (1<<31) +}; + +static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t) +{ + return (((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT)); +} + + /* Run sctp_add_cmd() generating a BUG() if there is a failure. */ static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) { @@ -449,7 +457,7 @@ * tag and the T bit is set in the Chunk Flags. */ static inline int -sctp_vtag_verify_either(const sctp_chunk_t *chunk, +sctp_vtag_verify_either(const struct sctp_chunk *chunk, const struct sctp_association *asoc) { /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2 diff -urN linux-2.4.25/include/net/sctp/structs.h linux-2.4.26/include/net/sctp/structs.h --- linux-2.4.25/include/net/sctp/structs.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/structs.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001-2003 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -14,7 +14,7 @@ * * The SCTP reference implementation 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. * @@ -31,18 +31,21 @@ * http://www.sf.net/projects/lksctp * * Written or modified by: - * Randall Stewart - * Ken Morneau - * Qiaobing Xie + * Randall Stewart + * Ken Morneau + * Qiaobing Xie * La Monte H.P. Yarroll - * Karl Knutson - * Jon Grimm - * Xingang Guo - * Hui Huang - * Sridhar Samudrala + * Karl Knutson + * Jon Grimm + * Xingang Guo + * Hui Huang + * Sridhar Samudrala * Daisy Chang - * Dajiang Zhang - * Ardelle Fan + * Dajiang Zhang + * Ardelle Fan + * Ryan Layer + * Anup Pemmaiah + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -54,12 +57,12 @@ #include /* We get struct timespec. */ #include /* linux/in.h needs this!! */ #include /* We get struct sockaddr_in. */ -#include /* We get struct in6_addr */ +#include /* We get struct in6_addr */ #include /* We get MAXHOSTNAMELEN. */ #include /* This gets us atomic counters. */ #include /* We need sk_buff_head. */ -#include /* We need sctp* header structs. */ -#include +#include /* We need tq_struct. */ +#include /* We need sctp* header structs. */ /* A convenience structure for handling sockaddr structures. * We should wean ourselves off this. @@ -70,9 +73,8 @@ struct sockaddr sa; }; - /* Forward declarations for data structures. */ -struct sctp_protocol; +struct sctp_globals; struct sctp_endpoint; struct sctp_association; struct sctp_transport; @@ -86,46 +88,45 @@ struct sctp_ep_common; struct sctp_ssnmap; -typedef struct sctp_chunk sctp_chunk_t; -typedef struct sctp_bind_addr sctp_bind_addr_t; +#include #include #include #include /* Structures useful for managing bind/connect. */ -typedef struct sctp_bind_bucket { - unsigned short port; +struct sctp_bind_bucket { + unsigned short port; unsigned short fastreuse; struct sctp_bind_bucket *next; struct sctp_bind_bucket **pprev; struct sock *sk; -} sctp_bind_bucket_t; +}; -typedef struct sctp_bind_hashbucket { +struct sctp_bind_hashbucket { spinlock_t lock; struct sctp_bind_bucket *chain; -} sctp_bind_hashbucket_t; +}; /* Used for hashing all associations. */ -typedef struct sctp_hashbucket { +struct sctp_hashbucket { rwlock_t lock; struct sctp_ep_common *chain; -} sctp_hashbucket_t __attribute__((__aligned__(8))); +} __attribute__((__aligned__(8))); -/* The SCTP protocol structure. */ -struct sctp_protocol { +/* The SCTP globals structure. */ +extern struct sctp_globals { /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values * * The following protocol parameters are RECOMMENDED: * - * RTO.Initial - 3 seconds - * RTO.Min - 1 second - * RTO.Max - 60 seconds - * RTO.Alpha - 1/8 (3 when converted to right shifts.) - * RTO.Beta - 1/4 (2 when converted to right shifts.) + * RTO.Initial - 3 seconds + * RTO.Min - 1 second + * RTO.Max - 60 seconds + * RTO.Alpha - 1/8 (3 when converted to right shifts.) + * RTO.Beta - 1/4 (2 when converted to right shifts.) */ __u32 rto_initial; __u32 rto_min; @@ -140,24 +141,24 @@ /* Max.Burst - 4 */ int max_burst; - /* Valid.Cookie.Life - 60 seconds */ + /* Valid.Cookie.Life - 60 seconds */ int valid_cookie_life; /* Whether Cookie Preservative is enabled(1) or not(0) */ int cookie_preserve_enable; /* Association.Max.Retrans - 10 attempts - * Path.Max.Retrans - 5 attempts (per destination address) - * Max.Init.Retransmits - 8 attempts + * Path.Max.Retrans - 5 attempts (per destination address) + * Max.Init.Retransmits - 8 attempts */ int max_retrans_association; int max_retrans_path; int max_retrans_init; - /* HB.interval - 30 seconds */ + /* HB.interval - 30 seconds */ int hb_interval; - /* The following variables are implementation specific. */ + /* The following variables are implementation specific. */ /* Default initialization values to be applied to new associations. */ __u16 max_instreams; @@ -170,102 +171,57 @@ /* This is the hash of all endpoints. */ int ep_hashsize; - sctp_hashbucket_t *ep_hashbucket; + struct sctp_hashbucket *ep_hashtable; /* This is the hash of all associations. */ int assoc_hashsize; - sctp_hashbucket_t *assoc_hashbucket; + struct sctp_hashbucket *assoc_hashtable; - /* This is the sctp port control hash. */ + /* This is the sctp port control hash. */ int port_hashsize; int port_rover; spinlock_t port_alloc_lock; /* Protects port_rover. */ - sctp_bind_hashbucket_t *port_hashtable; + struct sctp_bind_hashbucket *port_hashtable; /* This is the global local address list. * We actively maintain this complete list of interfaces on * the system by catching routing events. * - * It is a list of struct sockaddr_storage_list. + * It is a list of sctp_sockaddr_entry. */ struct list_head local_addr_list; spinlock_t local_addr_lock; -}; - - -/* - * Pointers to address related SCTP functions. - * (i.e. things that depend on the address family.) - */ -struct sctp_af { - int (*sctp_xmit) (struct sk_buff *skb, - struct sctp_transport *, - int ipfragok); - int (*setsockopt) (struct sock *sk, - int level, - int optname, - char *optval, - int optlen); - int (*getsockopt) (struct sock *sk, - int level, - int optname, - char *optval, - int *optlen); - struct dst_entry *(*get_dst) (struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr); - void (*get_saddr) (struct sctp_association *asoc, - struct dst_entry *dst, - union sctp_addr *daddr, - union sctp_addr *saddr); - void (*copy_addrlist) (struct list_head *, - struct net_device *); - void (*dst_saddr) (union sctp_addr *saddr, - struct dst_entry *dst, - unsigned short port); - int (*cmp_addr) (const union sctp_addr *addr1, - const union sctp_addr *addr2); - void (*addr_copy) (union sctp_addr *dst, - union sctp_addr *src); - void (*from_skb) (union sctp_addr *, - struct sk_buff *skb, - int saddr); - void (*from_sk) (union sctp_addr *, - struct sock *sk); - void (*to_sk_saddr) (union sctp_addr *, - struct sock *sk); - void (*to_sk_daddr) (union sctp_addr *, - struct sock *sk); - int (*addr_valid) (union sctp_addr *); - sctp_scope_t (*scope) (union sctp_addr *); - void (*inaddr_any) (union sctp_addr *, unsigned short); - int (*is_any) (const union sctp_addr *); - int (*available) (const union sctp_addr *); - int (*skb_iif) (const struct sk_buff *sk); - __u16 net_header_len; - int sockaddr_len; - sa_family_t sa_family; - struct list_head list; -}; - -struct sctp_af *sctp_get_af_specific(sa_family_t); -int sctp_register_af(struct sctp_af *); + + /* Flag to indicate if addip is enabled. */ + int addip_enable; +} sctp_globals; -/* Protocol family functions. */ -struct sctp_pf { - void (*event_msgname)(struct sctp_ulpevent *, char *, int *); - void (*skb_msgname) (struct sk_buff *, char *, int *); - int (*af_supported) (sa_family_t); - int (*cmp_addr) (const union sctp_addr *, - const union sctp_addr *, - struct sctp_opt *); - int (*bind_verify) (struct sctp_opt *, union sctp_addr *); - int (*send_verify) (struct sctp_opt *, union sctp_addr *); - int (*supported_addrs)(const struct sctp_opt *, __u16 *); - struct sock *(*create_accept_sk) (struct sock *sk, - struct sctp_association *asoc); - struct sctp_af *af; -}; +#define sctp_rto_initial (sctp_globals.rto_initial) +#define sctp_rto_min (sctp_globals.rto_min) +#define sctp_rto_max (sctp_globals.rto_max) +#define sctp_rto_alpha (sctp_globals.rto_alpha) +#define sctp_rto_beta (sctp_globals.rto_beta) +#define sctp_max_burst (sctp_globals.max_burst) +#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life) +#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable) +#define sctp_max_retrans_association (sctp_globals.max_retrans_association) +#define sctp_max_retrans_path (sctp_globals.max_retrans_path) +#define sctp_max_retrans_init (sctp_globals.max_retrans_init) +#define sctp_hb_interval (sctp_globals.hb_interval) +#define sctp_max_instreams (sctp_globals.max_instreams) +#define sctp_max_outstreams (sctp_globals.max_outstreams) +#define sctp_address_families (sctp_globals.address_families) +#define sctp_ep_hashsize (sctp_globals.ep_hashsize) +#define sctp_ep_hashtable (sctp_globals.ep_hashtable) +#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize) +#define sctp_assoc_hashtable (sctp_globals.assoc_hashtable) +#define sctp_port_hashsize (sctp_globals.port_hashsize) +#define sctp_port_rover (sctp_globals.port_rover) +#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock) +#define sctp_port_hashtable (sctp_globals.port_hashtable) +#define sctp_local_addr_list (sctp_globals.local_addr_list) +#define sctp_local_addr_lock (sctp_globals.local_addr_lock) +#define sctp_addip_enable (sctp_globals.addip_enable) /* SCTP Socket type: UDP or TCP style. */ typedef enum { @@ -291,14 +247,21 @@ /* Various Socket Options. */ __u16 default_stream; __u32 default_ppid; + __u16 default_flags; + __u32 default_context; + __u32 default_timetolive; + struct sctp_initmsg initmsg; struct sctp_rtoinfo rtoinfo; struct sctp_paddrparams paddrparam; struct sctp_event_subscribe subscribe; + struct sctp_assocparams assocparams; + int user_frag; __u32 autoclose; __u8 nodelay; __u8 disable_fragments; __u8 pd_mode; + __u8 v4mapped; /* Receive to here while partial delivery is in effect. */ struct sk_buff_head pd_lobby; @@ -315,22 +278,23 @@ * */ -typedef struct sctp_cookie { - /* My : Tag expected in every inbound packet and sent - * Verification: in the INIT or INIT ACK chunk. - * Tag : - */ - __u32 my_vtag; - - /* Peer's : Tag expected in every outbound packet except - * Verification: in the INIT chunk. - * Tag : - */ - __u32 peer_vtag; - - /* The rest of these are not from the spec, but really need to - * be in the cookie. - */ +struct sctp_cookie { + + /* My : Tag expected in every inbound packet and sent + * Verification: in the INIT or INIT ACK chunk. + * Tag : + */ + __u32 my_vtag; + + /* Peer's : Tag expected in every outbound packet except + * Verification: in the INIT chunk. + * Tag : + */ + __u32 peer_vtag; + + /* The rest of these are not from the spec, but really need to + * be in the cookie. + */ /* My Tie Tag : Assist in discovering a restarting association. */ __u32 my_ttag; @@ -338,16 +302,16 @@ /* Peer's Tie Tag: Assist in discovering a restarting association. */ __u32 peer_ttag; + /* When does this cookie expire? */ + struct timeval expiration; + /* Number of inbound/outbound streams which are set * and negotiated during the INIT process. */ __u16 sinit_num_ostreams; __u16 sinit_max_instreams; - /* When does this cookie expire? */ - struct timeval expiration __attribute__((packed)); - - /* This is the first sequence number I used. */ + /* This is the first sequence number I used. */ __u32 initial_tsn; /* This holds the originating address of the INIT packet. */ @@ -360,38 +324,38 @@ * the association TCB is re-constructed from the cookie. */ __u32 raw_addr_list_len; - sctp_init_chunk_t peer_init[0]; -} sctp_cookie_t __attribute__((aligned(4))); + struct sctp_init_chunk peer_init[0]; +}; /* The format of our cookie that we send to our peer. */ -typedef struct sctp_signed_cookie { +struct sctp_signed_cookie { __u8 signature[SCTP_SECRET_SIZE]; - sctp_cookie_t c; -} sctp_signed_cookie_t; + struct sctp_cookie c; +}; /* This is another convenience type to allocate memory for address * params for the maximum size and pass such structures around * internally. */ -typedef union { - sctp_ipv4addr_param_t v4; - sctp_ipv6addr_param_t v6; -} sctp_addr_param_t; +union sctp_addr_param { + struct sctp_ipv4addr_param v4; + struct sctp_ipv6addr_param v6; +}; /* A convenience type to allow walking through the various * parameters and avoid casting all over the place. */ union sctp_params { void *v; - sctp_paramhdr_t *p; - sctp_cookie_preserve_param_t *life; - sctp_hostname_param_t *dns; - sctp_cookie_param_t *cookie; - sctp_supported_addrs_param_t *sat; - sctp_ipv4addr_param_t *v4; - sctp_ipv6addr_param_t *v6; - sctp_addr_param_t *addr; + struct sctp_paramhdr *p; + struct sctp_cookie_preserve_param *life; + struct sctp_hostname_param *dns; + struct sctp_cookie_param *cookie; + struct sctp_supported_addrs_param *sat; + struct sctp_ipv4addr_param *v4; + struct sctp_ipv6addr_param *v6; + union sctp_addr_param *addr; }; /* RFC 2960. Section 3.3.5 Heartbeat. @@ -402,10 +366,10 @@ * HEARTBEAT is sent (see Section 8.3). */ typedef struct sctp_sender_hb_info { - sctp_paramhdr_t param_hdr; + struct sctp_paramhdr param_hdr; union sctp_addr daddr; unsigned long sent_at; -} sctp_sender_hb_info_t __attribute__((packed, aligned(4))); +} __attribute__((packed)) sctp_sender_hb_info_t; /* * RFC 2960 1.3.2 Sequenced Delivery within Streams @@ -443,12 +407,129 @@ return stream->ssn[id]; } -/* Return the next SSN number for this stream. */ +/* Return the next SSN number for this stream. */ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) { return stream->ssn[id]++; } +/* + * Pointers to address related SCTP functions. + * (i.e. things that depend on the address family.) + */ +struct sctp_af { + int (*sctp_xmit) (struct sk_buff *skb, + struct sctp_transport *, + int ipfragok); + int (*setsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int optlen); + int (*getsockopt) (struct sock *sk, + int level, + int optname, + char *optval, + int *optlen); + struct dst_entry *(*get_dst) (struct sctp_association *asoc, + union sctp_addr *daddr, + union sctp_addr *saddr); + void (*get_saddr) (struct sctp_association *asoc, + struct dst_entry *dst, + union sctp_addr *daddr, + union sctp_addr *saddr); + void (*copy_addrlist) (struct list_head *, + struct net_device *); + void (*dst_saddr) (union sctp_addr *saddr, + struct dst_entry *dst, + unsigned short port); + int (*cmp_addr) (const union sctp_addr *addr1, + const union sctp_addr *addr2); + void (*addr_copy) (union sctp_addr *dst, + union sctp_addr *src); + void (*from_skb) (union sctp_addr *, + struct sk_buff *skb, + int saddr); + void (*from_sk) (union sctp_addr *, + struct sock *sk); + void (*to_sk_saddr) (union sctp_addr *, + struct sock *sk); + void (*to_sk_daddr) (union sctp_addr *, + struct sock *sk); + void (*from_addr_param) (union sctp_addr *, + union sctp_addr_param *, + __u16 port, int iif); + int (*to_addr_param) (const union sctp_addr *, + union sctp_addr_param *); + int (*addr_valid) (union sctp_addr *, + struct sctp_opt *); + sctp_scope_t (*scope) (union sctp_addr *); + void (*inaddr_any) (union sctp_addr *, unsigned short); + int (*is_any) (const union sctp_addr *); + int (*available) (union sctp_addr *, + struct sctp_opt *); + int (*skb_iif) (const struct sk_buff *sk); + int (*is_ce) (const struct sk_buff *sk); + void (*seq_dump_addr)(struct seq_file *seq, + union sctp_addr *addr); + __u16 net_header_len; + int sockaddr_len; + sa_family_t sa_family; + struct list_head list; +}; + +struct sctp_af *sctp_get_af_specific(sa_family_t); +int sctp_register_af(struct sctp_af *); + +/* Protocol family functions. */ +struct sctp_pf { + void (*event_msgname)(struct sctp_ulpevent *, char *, int *); + void (*skb_msgname) (struct sk_buff *, char *, int *); + int (*af_supported) (sa_family_t, struct sctp_opt *); + int (*cmp_addr) (const union sctp_addr *, + const union sctp_addr *, + struct sctp_opt *); + int (*bind_verify) (struct sctp_opt *, union sctp_addr *); + int (*send_verify) (struct sctp_opt *, union sctp_addr *); + int (*supported_addrs)(const struct sctp_opt *, __u16 *); + struct sock *(*create_accept_sk) (struct sock *sk, + struct sctp_association *asoc); + void (*addr_v4map) (struct sctp_opt *, union sctp_addr *); + struct sctp_af *af; +}; + + +/* Structure to track chunk fragments that have been acked, but peer + * fragments of the same message have not. + */ +struct sctp_datamsg { + /* Chunks waiting to be submitted to lower layer. */ + struct list_head chunks; + /* Chunks that have been transmitted. */ + struct list_head track; + /* Reference counting. */ + atomic_t refcnt; + /* When is this message no longer interesting to the peer? */ + unsigned long expires_at; + /* Did the messenge fail to send? */ + int send_error; + char send_failed; + /* Control whether fragments from this message can expire. */ + char can_expire; +}; + +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, + struct sctp_sndrcvinfo *, + struct msghdr *, int len); +struct sctp_datamsg *sctp_datamsg_new(int gfp); +void sctp_datamsg_put(struct sctp_datamsg *); +void sctp_datamsg_hold(struct sctp_datamsg *); +void sctp_datamsg_free(struct sctp_datamsg *); +void sctp_datamsg_track(struct sctp_chunk *); +void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *); +void sctp_datamsg_fail(struct sctp_chunk *, int error); +int sctp_datamsg_expires(struct sctp_chunk *); + /* RFC2960 1.4 Key Terms * @@ -463,9 +544,10 @@ * three elements of struct sk_buff. This allows us to reuse * all the skb_* queue management functions. */ - sctp_chunk_t *next; - sctp_chunk_t *prev; + struct sctp_chunk *next; + struct sctp_chunk *prev; struct sk_buff_head *list; + atomic_t refcnt; /* This is our link to the per-transport transmitted list. */ struct list_head transmitted_list; @@ -490,23 +572,23 @@ union sctp_params param_hdr; union { __u8 *v; - sctp_datahdr_t *data_hdr; - sctp_inithdr_t *init_hdr; - sctp_sackhdr_t *sack_hdr; - sctp_heartbeathdr_t *hb_hdr; - sctp_sender_hb_info_t *hbs_hdr; - sctp_shutdownhdr_t *shutdown_hdr; - sctp_signed_cookie_t *cookie_hdr; - sctp_ecnehdr_t *ecne_hdr; - sctp_cwrhdr_t *ecn_cwr_hdr; - sctp_errhdr_t *err_hdr; + struct sctp_datahdr *data_hdr; + struct sctp_inithdr *init_hdr; + struct sctp_sackhdr *sack_hdr; + struct sctp_heartbeathdr *hb_hdr; + struct sctp_sender_hb_info *hbs_hdr; + struct sctp_shutdownhdr *shutdown_hdr; + struct sctp_signed_cookie *cookie_hdr; + struct sctp_ecnehdr *ecne_hdr; + struct sctp_cwrhdr *ecn_cwr_hdr; + struct sctp_errhdr *err_hdr; + struct sctp_addiphdr *addip_hdr; } subh; __u8 *chunk_end; - sctp_chunkhdr_t *chunk_hdr; - - sctp_sctphdr_t *sctp_hdr; + struct sctp_chunkhdr *chunk_hdr; + struct sctphdr *sctp_hdr; /* This needs to be recoverable for SCTP_SEND_FAILED events. */ struct sctp_sndrcvinfo sinfo; @@ -520,50 +602,59 @@ /* We fill this in if we are calculating RTT. */ unsigned long sent_at; - __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ - __u8 num_times_sent; /* How man times did we send this? */ - __u8 has_tsn; /* Does this chunk have a TSN yet? */ - __u8 has_ssn; /* Does this chunk have a SSN yet? */ - __u8 singleton; /* Was this the only chunk in the packet? */ - __u8 end_of_packet; /* Was this the last chunk in the packet? */ - __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ - __u8 pdiscard; /* Discard the whole packet now? */ - __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ - __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ - __u8 tsn_missing_report; /* Data chunk missing counter. */ - /* What is the origin IP address for this chunk? */ union sctp_addr source; /* Destination address for this chunk. */ union sctp_addr dest; + /* For outbound message, track all fragments for SEND_FAILED. */ + struct sctp_datamsg *msg; + /* For an inbound chunk, this tells us where it came from. * For an outbound chunk, it tells us where we'd like it to - * go. It is NULL if we have no preference. + * go. It is NULL if we have no preference. */ struct sctp_transport *transport; + + __u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */ + __u8 resent; /* Has this chunk ever been retransmitted. */ + __u8 has_tsn; /* Does this chunk have a TSN yet? */ + __u8 has_ssn; /* Does this chunk have a SSN yet? */ + __u8 singleton; /* Was this the only chunk in the packet? */ + __u8 end_of_packet; /* Was this the last chunk in the packet? */ + __u8 ecn_ce_done; /* Have we processed the ECN CE bit? */ + __u8 pdiscard; /* Discard the whole packet now? */ + __u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */ + __u8 fast_retransmit; /* Is this chunk fast retransmitted? */ + __u8 tsn_missing_report; /* Data chunk missing counter. */ }; -sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type, - __u8 flags, int size); -void sctp_free_chunk(sctp_chunk_t *); -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data); -sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *, - struct sock *); -void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *); -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk); +void sctp_chunk_hold(struct sctp_chunk *); +void sctp_chunk_put(struct sctp_chunk *); +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data); +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type, + __u8 flags, int size); +void sctp_chunk_free(struct sctp_chunk *); +void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); +struct sctp_chunk *sctp_chunkify(struct sk_buff *, + const struct sctp_association *, + struct sock *); +void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, + union sctp_addr *); +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ /* sin_family -- AF_INET or AF_INET6 * sin_port -- ordinary port number * sin_addr -- cast to either (struct in_addr) or (struct in6_addr) */ -struct sockaddr_storage_list { +struct sctp_sockaddr_entry { struct list_head list; union sctp_addr a; }; -typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *); +typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); /* This structure holds lists of chunks as we are assembling for * transmission. @@ -611,22 +702,22 @@ typedef int (sctp_outq_ehandler_t)(struct sctp_outq *); typedef struct sctp_packet *(sctp_outq_ohandler_init_t) (struct sctp_packet *, - struct sctp_transport *, - __u16 sport, - __u16 dport); + struct sctp_transport *, + __u16 sport, + __u16 dport); typedef struct sctp_packet *(sctp_outq_ohandler_config_t) - (struct sctp_packet *, + (struct sctp_packet *, __u32 vtag, int ecn_capable, sctp_packet_phandler_t *get_prepend_chunk); typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, - sctp_chunk_t *); + struct sctp_chunk *); typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); sctp_outq_ohandler_init_t sctp_packet_init; sctp_outq_ohandler_config_t sctp_packet_config; -sctp_outq_ohandler_t sctp_packet_append_chunk; -sctp_outq_ohandler_t sctp_packet_transmit_chunk; +sctp_outq_ohandler_t sctp_packet_append_chunk; +sctp_outq_ohandler_t sctp_packet_transmit_chunk; sctp_outq_ohandler_force_t sctp_packet_transmit; void sctp_packet_free(struct sctp_packet *); @@ -636,19 +727,19 @@ * * RFC2960 Section 1.4 Key Terms * - * o Transport address: A Transport Address is traditionally defined - * by Network Layer address, Transport Layer protocol and Transport - * Layer port number. In the case of SCTP running over IP, a - * transport address is defined by the combination of an IP address - * and an SCTP port number (where SCTP is the Transport protocol). + * o Transport address: A Transport Address is traditionally defined + * by Network Layer address, Transport Layer protocol and Transport + * Layer port number. In the case of SCTP running over IP, a + * transport address is defined by the combination of an IP address + * and an SCTP port number (where SCTP is the Transport protocol). * * RFC2960 Section 7.1 SCTP Differences from TCP Congestion control * - * o The sender keeps a separate congestion control parameter set for - * each of the destination addresses it can send to (not each - * source-destination pair but for each destination). The parameters - * should decay if the address is not used for a long enough time - * period. + * o The sender keeps a separate congestion control parameter set for + * each of the destination addresses it can send to (not each + * source-destination pair but for each destination). The parameters + * should decay if the address is not used for a long enough time + * period. * */ struct sctp_transport { @@ -657,12 +748,12 @@ /* Reference counting. */ atomic_t refcnt; - int dead; + int dead; /* This is the peer's IP address and port. */ union sctp_addr ipaddr; - /* These are the functions we call to handle LLP stuff. */ + /* These are the functions we call to handle LLP stuff. */ struct sctp_af *af_specific; /* Which association do we belong to? */ @@ -676,33 +767,33 @@ * address list derived from the INIT or INIT ACK chunk, a * number of data elements needs to be maintained including: */ - __u32 rtt; /* This is the most recent RTT. */ + __u32 rtt; /* This is the most recent RTT. */ - /* RTO : The current retransmission timeout value. */ + /* RTO : The current retransmission timeout value. */ __u32 rto; /* RTTVAR : The current RTT variation. */ __u32 rttvar; - /* SRTT : The current smoothed round trip time. */ + /* SRTT : The current smoothed round trip time. */ __u32 srtt; /* RTO-Pending : A flag used to track if one of the DATA - * chunks sent to this address is currently being - * used to compute a RTT. If this flag is 0, - * the next DATA chunk sent to this destination - * should be used to compute a RTT and this flag - * should be set. Every time the RTT - * calculation completes (i.e. the DATA chunk - * is SACK'd) clear this flag. - */ + * chunks sent to this address is currently being + * used to compute a RTT. If this flag is 0, + * the next DATA chunk sent to this destination + * should be used to compute a RTT and this flag + * should be set. Every time the RTT + * calculation completes (i.e. the DATA chunk + * is SACK'd) clear this flag. + */ int rto_pending; /* * These are the congestion stats. */ - /* cwnd : The current congestion window. */ - __u32 cwnd; /* This is the actual cwnd. */ + /* cwnd : The current congestion window. */ + __u32 cwnd; /* This is the actual cwnd. */ /* ssthresh : The current slow start threshold value. */ __u32 ssthresh; @@ -715,7 +806,7 @@ /* Data that has been sent, but not acknowledged. */ __u32 flight_size; - /* PMTU : The current known path MTU. */ + /* PMTU : The current known path MTU. */ __u32 pmtu; /* Destination */ @@ -745,23 +836,23 @@ unsigned long last_time_ecne_reduced; /* active : The current active state of this destination, - * : i.e. DOWN, UP, etc. + * : i.e. DOWN, UP, etc. */ int active; /* hb_allowed : The current heartbeat state of this destination, - * : i.e. ALLOW-HB, NO-HEARTBEAT, etc. + * : i.e. ALLOW-HB, NO-HEARTBEAT, etc. */ int hb_allowed; /* These are the error stats for this destination. */ - /* Error count : The current error count for this destination. */ + /* Error count : The current error count for this destination. */ unsigned short error_count; /* Error : Current error threshold for this destination * Threshold : i.e. what value marks the destination down if - * : errorCount reaches this value. + * : errorCount reaches this value. */ unsigned short error_threshold; @@ -771,10 +862,7 @@ */ int max_retrans; - /* We use this name for debugging output... */ - char *debug_name; - - /* Per : A timer used by each destination. + /* Per : A timer used by each destination. * Destination : * Timer : * @@ -799,6 +887,35 @@ struct list_head send_ready; int malloced; /* Is this structure kfree()able? */ + + /* State information saved for SFR_CACC algorithm. The key + * idea in SFR_CACC is to maintain state at the sender on a + * per-destination basis when a changeover happens. + * char changeover_active; + * char cycling_changeover; + * __u32 next_tsn_at_change; + * char cacc_saw_newack; + */ + struct { + /* An unsigned integer, which stores the next TSN to be + * used by the sender, at the moment of changeover. + */ + __u32 next_tsn_at_change; + + /* A flag which indicates the occurrence of a changeover */ + char changeover_active; + + /* A glag which indicates whether the change of primary is + * the first switch to this destination address during an + * active switch. + */ + char cycling_changeover; + + /* A temporary flag, which is used during the processing of + * a SACK to estimate the causative TSN(s)'s group. + */ + char cacc_saw_newack; + } cacc; }; struct sctp_transport *sctp_transport_new(const union sctp_addr *, int); @@ -831,20 +948,20 @@ /* This is the packet which is currently off the in queue and is * being worked on through the inbound chunk processing. */ - sctp_chunk_t *in_progress; + struct sctp_chunk *in_progress; /* This is the delayed task to finish delivering inbound * messages. */ struct tq_struct immediate; - int malloced; /* Is this structure kfree()able? */ + int malloced; /* Is this structure kfree()able? */ }; struct sctp_inq *sctp_inq_new(void); void sctp_inq_init(struct sctp_inq *); void sctp_inq_free(struct sctp_inq *); -void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet); +void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet); struct sctp_chunk *sctp_inq_pop(struct sctp_inq *); void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); @@ -855,7 +972,7 @@ * This structure covers sections 6.3, 6.4, 6.7, 6.8, 6.10, 7., 8.1, * and 8.2 of the v13 draft. * - * It handles retransmissions. The connection to the timeout portion + * It handles retransmissions. The connection to the timeout portion * of the state machine is through sctp_..._timeout() and timeout_handler. * * If you feed it SACKs, it will eat them. @@ -901,23 +1018,26 @@ sctp_outq_ohandler_t *build_output; sctp_outq_ohandler_force_t *force_output; - /* How many unackd bytes do we have in-flight? */ + /* How many unackd bytes do we have in-flight? */ __u32 outstanding_bytes; + /* Corked? */ + char cork; + /* Is this structure empty? */ - int empty; + char empty; /* Are we kfree()able? */ - int malloced; + char malloced; }; struct sctp_outq *sctp_outq_new(struct sctp_association *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_teardown(struct sctp_outq *); void sctp_outq_free(struct sctp_outq*); -int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk); +int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk); int sctp_outq_flush(struct sctp_outq *, int); -int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *); +int sctp_outq_sack(struct sctp_outq *, struct sctp_sackhdr *); int sctp_outq_is_empty(const struct sctp_outq *); int sctp_outq_set_output_handlers(struct sctp_outq *, sctp_outq_ohandler_init_t init, @@ -926,18 +1046,24 @@ sctp_outq_ohandler_t build, sctp_outq_ohandler_force_t force); void sctp_outq_restart(struct sctp_outq *); + void sctp_retransmit(struct sctp_outq *, struct sctp_transport *, sctp_retransmit_reason_t); void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); - +int sctp_outq_uncork(struct sctp_outq *); +/* Uncork and flush an outqueue. */ +static inline void sctp_outq_cork(struct sctp_outq *q) +{ + q->cork = 1; +} /* These bind address data fields common between endpoints and associations */ struct sctp_bind_addr { /* RFC 2960 12.1 Parameters necessary for the SCTP instance * - * SCTP Port: The local SCTP port number the endpoint is - * bound to. + * SCTP Port: The local SCTP port number the endpoint is + * bound to. */ __u16 port; @@ -949,19 +1075,24 @@ */ struct list_head address_list; - int malloced; /* Are we kfree()able? */ + int malloced; /* Are we kfree()able? */ }; -sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask); -void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port); -void sctp_bind_addr_free(sctp_bind_addr_t *); -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask); +void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); +void sctp_bind_addr_free(struct sctp_bind_addr *); +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp,int flags); -int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, +int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, int gfp); -int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); -int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *, +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); +int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_opt *); +union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, + const union sctp_addr *addrs, + int addrcnt, + struct sctp_opt *opt); union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp); int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len, @@ -985,13 +1116,13 @@ * local endpoint. * This common structure is useful for several purposes: * 1) Common interface for lookup routines. - * a) Subfunctions work for either endpoint or association - * b) Single interface to lookup allows hiding the lookup lock rather - * than acquiring it externally. + * a) Subfunctions work for either endpoint or association + * b) Single interface to lookup allows hiding the lookup lock rather + * than acquiring it externally. * 2) Common interface for the inbound chunk handling/state machine. * 3) Common object handling routines for reference counting, etc. * 4) Disentangle association lookup from endpoint lookup, where we - * do not have to find our endpoint to find our association. + * do not have to find our endpoint to find our association. * */ @@ -1010,21 +1141,21 @@ * malloced - Do we need to kfree this object? */ atomic_t refcnt; - char dead; - char malloced; + char dead; + char malloced; /* What socket does this endpoint belong to? */ struct sock *sk; /* This is where we receive inbound chunks. */ - struct sctp_inq inqueue; + struct sctp_inq inqueue; /* This substructure includes the defining parameters of the * endpoint: * bind_addr.port is our shared port number. * bind_addr.address_list is our set of local IP addresses. */ - sctp_bind_addr_t bind_addr; + struct sctp_bind_addr bind_addr; /* Protection during address list comparisons. */ rwlock_t addr_lock; @@ -1055,22 +1186,22 @@ struct sctp_ep_common base; /* Associations: A list of current associations and mappings - * to the data consumers for each association. This - * may be in the form of a hash table or other - * implementation dependent structure. The data - * consumers may be process identification - * information such as file descriptors, named pipe - * pointer, or table pointers dependent on how SCTP - * is implemented. + * to the data consumers for each association. This + * may be in the form of a hash table or other + * implementation dependent structure. The data + * consumers may be process identification + * information such as file descriptors, named pipe + * pointer, or table pointers dependent on how SCTP + * is implemented. */ /* This is really a list of struct sctp_association entries. */ struct list_head asocs; /* Secret Key: A secret key used by this endpoint to compute - * the MAC. This SHOULD be a cryptographic quality - * random number with a sufficient length. + * the MAC. This SHOULD be a cryptographic quality + * random number with a sufficient length. * Discussion in [RFC1750] can be helpful in - * selection of the key. + * selection of the key. */ __u8 secret_key[SCTP_HOW_MANY_SECRETS][SCTP_SECRET_SIZE]; int current_key; @@ -1080,7 +1211,7 @@ /* Default timeouts. */ int timeouts[SCTP_NUM_TIMEOUT_TYPES]; - /* Various thresholds. */ + /* Various thresholds. */ /* Name for debugging output... */ char *debug_name; @@ -1157,11 +1288,11 @@ */ __u32 eyecatcher; - /* This is our parent endpoint. */ + /* This is our parent endpoint. */ struct sctp_endpoint *ep; /* These are those association elements needed in the cookie. */ - sctp_cookie_t c; + struct sctp_cookie c; /* This is all information about our peer. */ struct { @@ -1173,11 +1304,11 @@ /* transport_addr_list * - * Peer : A list of SCTP transport addresses that the + * Peer : A list of SCTP transport addresses that the * Transport : peer is bound to. This information is derived * Address : from the INIT or INIT ACK and is used to - * List : associate an inbound packet with a given - * : association. Normally this information is + * List : associate an inbound packet with a given + * : association. Normally this information is * : hashed or keyed for quick lookup and access * : of the TCB. * @@ -1193,8 +1324,8 @@ /* primary_path * * Primary : This is the current primary destination - * Path : transport address of the peer endpoint. It - * : may also specify a source transport address + * Path : transport address of the peer endpoint. It + * : may also specify a source transport address * : on this endpoint. * * All of these paths live on transport_addr_list. @@ -1233,25 +1364,25 @@ /* Pointer to last transport I have sent on. */ struct sctp_transport *last_sent_to; - /* This is the last transport I have received DATA on. */ + /* This is the last transport I have received DATA on. */ struct sctp_transport *last_data_from; /* * Mapping An array of bits or bytes indicating which out of * Array order TSN's have been received (relative to the - * Last Rcvd TSN). If no gaps exist, i.e. no out of - * order packets have been received, this array - * will be set to all zero. This structure may be - * in the form of a circular buffer or bit array. + * Last Rcvd TSN). If no gaps exist, i.e. no out of + * order packets have been received, this array + * will be set to all zero. This structure may be + * in the form of a circular buffer or bit array. * * Last Rcvd : This is the last TSN received in * TSN : sequence. This value is set initially by - * : taking the peer's Initial TSN, received in - * : the INIT or INIT ACK chunk, and subtracting - * : one from it. + * : taking the peer's Initial TSN, received in + * : the INIT or INIT ACK chunk, and subtracting + * : one from it. * * Throughout most of the specification this is called the - * "Cumulative TSN ACK Point". In this case, we + * "Cumulative TSN ACK Point". In this case, we * ignore the advice in 12.2 in favour of the term * used in the bulk of the text. This value is hidden * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn(). @@ -1260,39 +1391,47 @@ __u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)]; /* Do we need to sack the peer? */ - __u8 sack_needed; + __u8 sack_needed; /* These are capabilities which our peer advertised. */ - __u8 ecn_capable; /* Can peer do ECN? */ - __u8 ipv4_address; /* Peer understands IPv4 addresses? */ - __u8 ipv6_address; /* Peer understands IPv6 addresses? */ + __u8 ecn_capable; /* Can peer do ECN? */ + __u8 ipv4_address; /* Peer understands IPv4 addresses? */ + __u8 ipv6_address; /* Peer understands IPv6 addresses? */ __u8 hostname_address;/* Peer understands DNS addresses? */ - sctp_inithdr_t i; + + /* Does peer support ADDIP? */ + __u8 asconf_capable; + + /* This mask is used to disable sending the ASCONF chunk + * with specified parameter to peer. + */ + __u16 addip_disabled_mask; + + struct sctp_inithdr i; int cookie_len; void *cookie; - /* ADDIP Extention (ADDIP) --xguo */ - /* minus 1 (ADDIP sec. 4.2 C1) */ + /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. + * C1) ... "Peer-Serial-Number'. This value MUST be initialized to the + * Initial TSN Value minus 1 + */ __u32 addip_serial; } peer; /* State : A state variable indicating what state the * : association is in, i.e. COOKIE-WAIT, - * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, - * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. + * : COOKIE-ECHOED, ESTABLISHED, SHUTDOWN-PENDING, + * : SHUTDOWN-SENT, SHUTDOWN-RECEIVED, SHUTDOWN-ACK-SENT. * - * Note: No "CLOSED" state is illustrated since if a - * association is "CLOSED" its TCB SHOULD be removed. + * Note: No "CLOSED" state is illustrated since if a + * association is "CLOSED" its TCB SHOULD be removed. * - * In this implementation we DO have a CLOSED + * In this implementation we DO have a CLOSED * state which is used during initiation and shutdown. * - * State takes values from SCTP_STATE_*. + * State takes values from SCTP_STATE_*. */ sctp_state_t state; - /* When did we enter this state? */ - int state_timestamp; - /* The cookie life I award for any cookie. */ struct timeval cookie_life; @@ -1301,12 +1440,6 @@ */ int overall_error_count; - /* Overall : The threshold for this association that if - * Error : the Overall Error Count reaches will cause - * Threshold : this association to be torn down. - */ - int overall_error_threshold; - /* These are the association's initial, max, and min RTO values. * These values will be initialized by system defaults, but can * be modified via the SCTP_RTOINFO socket option. @@ -1333,7 +1466,6 @@ /* The largest timeout or RTO value to use in attempting an INIT */ __u16 max_init_timeo; - int timeouts[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; @@ -1341,19 +1473,19 @@ struct sctp_transport *shutdown_last_sent_to; /* Next TSN : The next TSN number to be assigned to a new - * : DATA chunk. This is sent in the INIT or INIT - * : ACK chunk to the peer and incremented each - * : time a DATA chunk is assigned a TSN - * : (normally just prior to transmit or during + * : DATA chunk. This is sent in the INIT or INIT + * : ACK chunk to the peer and incremented each + * : time a DATA chunk is assigned a TSN + * : (normally just prior to transmit or during * : fragmentation). */ __u32 next_tsn; /* * Last Rcvd : This is the last TSN received in sequence. This value - * TSN : is set initially by taking the peer's Initial TSN, - * : received in the INIT or INIT ACK chunk, and - * : subtracting one from it. + * TSN : is set initially by taking the peer's Initial TSN, + * : received in the INIT or INIT ACK chunk, and + * : subtracting one from it. * * Most of RFC 2960 refers to this as the Cumulative TSN Ack Point. */ @@ -1393,7 +1525,7 @@ wait_queue_head_t wait; /* Association : The smallest PMTU discovered for all of the - * PMTU : peer's transport addresses. + * PMTU : peer's transport addresses. */ __u32 pmtu; @@ -1401,29 +1533,28 @@ __u32 frag_point; /* Ack State : This flag indicates if the next received - * : packet is to be responded to with a - * : SACK. This is initializedto 0. When a packet - * : is received it is incremented. If this value - * : reaches 2 or more, a SACK is sent and the - * : value is reset to 0. Note: This is used only - * : when no DATA chunks are received out of - * : order. When DATA chunks are out of order, - * : SACK's are not delayed (see Section 6). + * : packet is to be responded to with a + * : SACK. This is initializedto 0. When a packet + * : is received it is incremented. If this value + * : reaches 2 or more, a SACK is sent and the + * : value is reset to 0. Note: This is used only + * : when no DATA chunks are received out of + * : order. When DATA chunks are out of order, + * : SACK's are not delayed (see Section 6). */ /* Do we need to send an ack? * When counters[SctpCounterAckState] is above 1 we do! */ int counters[SCTP_NUMBER_COUNTERS]; - struct { - __u16 stream; - __u16 flags; - __u32 ppid; - __u32 context; - __u32 timetolive; - } defaults; + /* Default send parameters. */ + __u16 default_stream; + __u16 default_flags; + __u32 default_ppid; + __u32 default_context; + __u32 default_timetolive; - /* This tracks outbound ssn for a given stream. */ + /* This tracks outbound ssn for a given stream. */ struct sctp_ssnmap *ssnmap; /* All outbound chunks go through this structure. */ @@ -1434,13 +1565,10 @@ */ struct sctp_ulpq ulpq; - /* Need to send an ECNE Chunk? */ - int need_ecne; - /* Last TSN that caused an ECNE Chunk to be sent. */ __u32 last_ecne_tsn; - /* Last TSN that caused a CWR Chunk to be sent. */ + /* Last TSN that caused a CWR Chunk to be sent. */ __u32 last_cwr_tsn; /* How many duplicated TSNs have we seen? */ @@ -1449,9 +1577,6 @@ /* Number of seconds of idle time before an association is closed. */ __u32 autoclose; - /* Name for debugging output... */ - char *debug_name; - /* These are to support * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses * and Enforcement of Flow and Message Limits" @@ -1459,8 +1584,7 @@ * or "ADDIP" for short. */ - /* Is the ADDIP extension enabled for this association? */ - int addip_enable; + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks * @@ -1476,7 +1600,7 @@ * [This is our one-and-only-one ASCONF in flight. If we do * not have an ASCONF in flight, this is NULL.] */ - sctp_chunk_t *addip_last_asconf; + struct sctp_chunk *addip_last_asconf; /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. * @@ -1491,7 +1615,7 @@ * [This is our saved ASCONF-ACK. We invalidate it when a new * ASCONF serial number arrives.] */ - sctp_chunk_t *addip_last_asconf_ack; + struct sctp_chunk *addip_last_asconf_ack; /* These ASCONF chunks are waiting to be sent. * @@ -1504,7 +1628,7 @@ * * In defining the ASCONF Chunk transfer procedures, it is * essential that these transfers MUST NOT cause congestion - * within the network. To achieve this, we place these + * within the network. To achieve this, we place these * restrictions on the transfer of ASCONF Chunks: * * R1) One and only one ASCONF Chunk MAY be in transit and @@ -1518,20 +1642,20 @@ * * * [I really think this is EXACTLY the sort of intelligence - * which already resides in sctp_outq. Please move this - * queue and its supporting logic down there. --piggy] + * which already resides in sctp_outq. Please move this + * queue and its supporting logic down there. --piggy] */ struct sk_buff_head addip_chunks; /* ADDIP Section 4.1 ASCONF Chunk Procedures * * A2) A serial number should be assigned to the Chunk. The - * serial number should be a monotonically increasing - * number. All serial numbers are defined to be initialized at + * serial number SHOULD be a monotonically increasing + * number. The serial number SHOULD be initialized at * the start of the association to the same value as the - * Initial TSN. - * - * [and] + * Initial TSN and every time a new ASCONF chunk is created + * it is incremented by one after assigning the serial number + * to the newly created chunk. * * ADDIP * 3.1.1 Address/Stream Configuration Change Chunk (ASCONF) @@ -1540,13 +1664,16 @@ * * This value represents a Serial Number for the ASCONF * Chunk. The valid range of Serial Number is from 0 to - * 4294967295 (2**32 - 1). Serial Numbers wrap back to 0 + * 4294967295 (2^32 - 1). Serial Numbers wrap back to 0 * after reaching 4294967295. */ __u32 addip_serial; - /* Is it a temporary association? */ - __u8 temp; + /* Need to send an ECNE Chunk? */ + char need_ecne; + + /* Is it a temporary association? */ + char temp; }; @@ -1566,7 +1693,7 @@ return asoc; } -/* These are function signatures for manipulating associations. */ +/* These are function signatures for manipulating associations. */ struct sctp_association * @@ -1585,9 +1712,13 @@ void sctp_assoc_update_retran_path(struct sctp_association *); struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *, const union sctp_addr *); +int sctp_assoc_lookup_laddr(struct sctp_association *asoc, + const union sctp_addr *laddr); struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *, const union sctp_addr *address, const int gfp); +void sctp_assoc_del_peer(struct sctp_association *asoc, + const union sctp_addr *addr); void sctp_assoc_control_transport(struct sctp_association *, struct sctp_transport *, sctp_transport_cmd_t, sctp_sn_error_t); @@ -1603,18 +1734,18 @@ __u32 sctp_association_get_tsn_block(struct sctp_association *, int); void sctp_assoc_sync_pmtu(struct sctp_association *); -void sctp_assoc_rwnd_increase(struct sctp_association *, int); -void sctp_assoc_rwnd_decrease(struct sctp_association *, int); +void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned); +void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned); void sctp_assoc_set_primary(struct sctp_association *, struct sctp_transport *); int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, int); int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *, - sctp_cookie_t *, int gfp); + struct sctp_cookie*, int gfp); int sctp_cmp_addr_exact(const union sctp_addr *ss1, - const union sctp_addr *ss2); -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc); -sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc); + const union sctp_addr *ss2); +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc); +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc); /* A convenience structure to parse out SCTP specific CMSGs. */ typedef struct sctp_cmsgs { diff -urN linux-2.4.25/include/net/sctp/tsnmap.h linux-2.4.26/include/net/sctp/tsnmap.h --- linux-2.4.25/include/net/sctp/tsnmap.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/tsnmap.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,5 +1,8 @@ -/* SCTP kernel reference Implementation Copyright (C) 1999-2001 - * Cisco, Motorola, Intel, and International Business Machines Corp. +/* SCTP kernel reference Implementation + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2001-2003 International Business Machines, Corp. + * Copyright (c) 2001 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -97,13 +100,16 @@ /* Data chunks pending receipt. used by SCTP_STATUS sockopt */ __u16 pending_data; - /* We record duplicate TSNs here. We clear this after + /* Record duplicate TSNs here. We clear this after * every SACK. Store up to SCTP_MAX_DUP_TSNS worth of * information. */ __u32 dup_tsns[SCTP_MAX_DUP_TSNS]; __u16 num_dup_tsns; + /* Record gap ack block information here. */ + struct sctp_gap_ack_block gabs[SCTP_MAX_GABS]; + int malloced; __u8 raw_map[0]; @@ -140,12 +146,18 @@ void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn); /* Retrieve the Cumulative TSN ACK Point. */ -__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *); +static inline __u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map) +{ + return map->cumulative_tsn_ack_point; +} /* Retrieve the highest TSN we've seen. */ -__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *); +static inline __u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map) +{ + return map->max_tsn_seen; +} -/* How many Duplicate TSNs are stored? */ +/* How many duplicate TSNs are stored? */ static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map) { return map->num_dup_tsns; @@ -158,6 +170,27 @@ return map->dup_tsns; } +/* How many gap ack blocks do we have recorded? */ +__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map); + +/* Refresh the count on pending data. */ +__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map); + +/* Return pointer to gap ack blocks as needed by SACK. */ +static inline struct sctp_gap_ack_block *sctp_tsnmap_get_gabs(struct sctp_tsnmap *map) +{ + return map->gabs; +} + +/* Is there a gap in the TSN map? */ +static inline int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map) +{ + int has_gap; + + has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen); + return has_gap; +} + /* Mark a duplicate TSN. Note: limit the storage of duplicate TSN * information. */ diff -urN linux-2.4.25/include/net/sctp/ulpevent.h linux-2.4.26/include/net/sctp/ulpevent.h --- linux-2.4.25/include/net/sctp/ulpevent.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/ulpevent.h 2004-04-14 06:05:40.000000000 -0700 @@ -40,6 +40,7 @@ * Jon Grimm * La Monte H.P. Yarroll * Karl Knutson + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -48,8 +49,6 @@ #ifndef __sctp_ulpevent_h__ #define __sctp_ulpevent_h__ -#include - /* A structure to carry information to the ULP (e.g. Sockets API) */ /* Warning: This sits inside an skb.cb[] area. Be very careful of * growing this structure as it is at the maximum limit now. @@ -59,7 +58,6 @@ int msg_flags; int iif; }; -#define event_asoc sndrcvinfo.sinfo_assoc_id /* Retrieve the skb this event sits inside of. */ static inline struct sk_buff *sctp_event2skb(struct sctp_ulpevent *ev) @@ -74,9 +72,10 @@ } struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); +void sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); +void sctp_queue_purge_ulpevents(struct sk_buff_head *list); struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, diff -urN linux-2.4.25/include/net/sctp/user.h linux-2.4.26/include/net/sctp/user.h --- linux-2.4.25/include/net/sctp/user.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/sctp/user.h 2004-04-14 06:05:40.000000000 -0700 @@ -1,38 +1,39 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. - * + * Copyright (c) 2001-2003 International Business Machines, Corp. + * Copyright (c) 2002 Intel Corp. + * * This file is part of the SCTP kernel reference Implementation - * + * * This header represents the structures and constants needed to support - * the SCTP Extension to the Sockets API. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * the SCTP Extension to the Sockets API. + * + * The SCTP reference implementation 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. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll * R. Stewart * K. Morneau @@ -40,61 +41,63 @@ * Karl Knutson * Jon Grimm * Daisy Chang - * - * + * Ryan Layer + * Ardelle Fan + * Sridhar Samudrala + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -#include -#include #ifndef __net_sctp_user_h__ #define __net_sctp_user_h__ -struct sctp_association; -typedef struct sctp_association * sctp_assoc_t; +#include +#include + +typedef void * sctp_assoc_t; /* The following symbols come from the Sockets API Extensions for - * SCTP . + * SCTP . */ enum sctp_optname { SCTP_RTOINFO, #define SCTP_RTOINFO SCTP_RTOINFO - SCTP_ASSOCRTXINFO, -#define SCTP_ASSOCRTXINFO SCTP_ASSOCRTXINFO + SCTP_ASSOCINFO, +#define SCTP_ASSOCINFO SCTP_ASSOCINFO SCTP_INITMSG, #define SCTP_INITMSG SCTP_INITMSG - SCTP_AUTO_CLOSE, -#define SCTP_AUTO_CLOSE SCTP_AUTO_CLOSE - SCTP_SET_PRIMARY_ADDR, -#define SCTP_SET_PRIMARY_ADDR SCTP_SET_PRIMARY_ADDR + SCTP_NODELAY, /* Get/set nodelay option. */ +#define SCTP_NODELAY SCTP_NODELAY + SCTP_AUTOCLOSE, +#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE SCTP_SET_PEER_PRIMARY_ADDR, #define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR - SCTP_SET_ADAPTATION_LAYER, -#define SCTP_SET_ADAPTATION_LAYER SCTP_SET_ADAPTATION_LAYER - SCTP_SET_STREAM_TIMEOUTS, -#define SCTP_SET_STREAM_TIMEOUTS SCTP_SET_STREAM_TIMEOUTS + SCTP_PRIMARY_ADDR, +#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR + SCTP_ADAPTION_LAYER, +#define SCTP_ADAPTION_LAYER SCTP_ADAPTION_LAYER SCTP_DISABLE_FRAGMENTS, #define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS - SCTP_SET_PEER_ADDR_PARAMS, -#define SCTP_SET_PEER_ADDR_PARAMS SCTP_SET_PEER_ADDR_PARAMS - SCTP_GET_PEER_ADDR_PARAMS, -#define SCTP_GET_PEER_ADDR_PARAMS SCTP_GET_PEER_ADDR_PARAMS + SCTP_PEER_ADDR_PARAMS, +#define SCTP_PEER_ADDR_PARAMS SCTP_PEER_ADDR_PARAMS + SCTP_DEFAULT_SEND_PARAM, +#define SCTP_DEFAULT_SEND_PARAM SCTP_DEFAULT_SEND_PARAM + SCTP_EVENTS, +#define SCTP_EVENTS SCTP_EVENTS + SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ +#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG, /* Get/set maximum fragment. */ +#define SCTP_MAXSEG SCTP_MAXSEG SCTP_STATUS, #define SCTP_STATUS SCTP_STATUS SCTP_GET_PEER_ADDR_INFO, #define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO - SCTP_SET_EVENTS, -#define SCTP_SET_EVENTS SCTP_SET_EVENTS - SCTP_AUTOCLOSE, -#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE - SCTP_SET_DEFAULT_SEND_PARAM, -#define SCTP_SET_DEFAULT_SEND_PARAM SCTP_SET_DEFAULT_SEND_PARAM - SCTP_SOCKOPT_DEBUG_NAME = 42, /* FIXME */ -#define SCTP_SOCKOPT_DEBUG_NAME SCTP_SOCKOPT_DEBUG_NAME - - SCTP_SOCKOPT_BINDX_ADD, /* BINDX requests for adding addresses. */ + /* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ + SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */ #define SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_REM, /* BINDX requests for removing addresses. */ #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM @@ -108,25 +111,8 @@ #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS - SCTP_NODELAY, /* Get/set nodelay option. */ -#define SCTP_NODELAY SCTP_NODELAY }; - -/* - * 5.2 SCTP msg_control Structures - * - * A key element of all SCTP-specific socket extensions is the use of - * ancillary data to specify and access SCTP-specific data via the - * struct msghdr's msg_control member used in sendmsg() and recvmsg(). - * Fine-grained control over initialization and sending parameters are - * handled with ancillary data. - * - * Each ancillary data item is preceeded by a struct cmsghdr (see - * Section 5.1), which defines the function and purpose of the data - * contained in in the cmsg_data[] member. - */ - /* * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * @@ -147,7 +133,6 @@ __u16 sinit_max_init_timeo; }; - /* * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * @@ -209,7 +194,6 @@ * following format: * */ - struct sctp_assoc_change { __u16 sac_type; __u16 sac_flags; @@ -262,11 +246,11 @@ * event that happened to the address. They include: */ enum sctp_spc_state { - ADDRESS_AVAILABLE, - ADDRESS_UNREACHABLE, - ADDRESS_REMOVED, - ADDRESS_ADDED, - ADDRESS_MADE_PRIM, + SCTP_ADDR_REACHABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, }; @@ -285,7 +269,6 @@ __u16 sre_flags; __u32 sre_length; __u16 sre_error; - __u16 sre_len; sctp_assoc_t sre_assoc_id; __u8 sre_data[0]; }; @@ -319,7 +302,6 @@ * Note that this does not necessarily mean that the * data was (or was not) successfully delivered. */ - enum sctp_ssf_flags { SCTP_DATA_UNSENT, SCTP_DATA_SENT, @@ -331,7 +313,6 @@ * When a peer sends a SHUTDOWN, SCTP delivers this notification to * inform the application that it should cease sending data. */ - struct sctp_shutdown_event { __u16 sse_type; __u16 sse_flags; @@ -350,8 +331,8 @@ __u16 sai_type; __u16 sai_flags; __u32 sai_length; - __u32 sai_adaptation_bits; - sctp_assoc_t sse_assoc_id; + __u32 sai_adaption_ind; + sctp_assoc_t sai_assoc_id; }; /* @@ -361,8 +342,7 @@ * message this notification will be used to inidicate * various events. */ - -struct sctp_rcv_pdapi_event { +struct sctp_pdapi_event { __u16 pdapi_type; __u16 pdapi_flags; __u32 pdapi_length; @@ -399,14 +379,14 @@ __u16 sn_type; /* Notification type. */ __u16 sn_flags; __u32 sn_length; - } h; + } sn_header; struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_padr_change; + struct sctp_paddr_change sn_paddr_change; struct sctp_remote_error sn_remote_error; struct sctp_send_failed sn_send_failed; struct sctp_shutdown_event sn_shutdown_event; struct sctp_adaption_event sn_adaption_event; - struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; + struct sctp_pdapi_event sn_pdapi_event; }; /* Section 5.3.1 @@ -443,102 +423,110 @@ } sctp_sn_error_t; /* - * - * 7.1.14 Peer Address Parameters - * - * Applications can enable or disable heartbeats for any peer address - * of an association, modify an address's heartbeat interval, force a - * heartbeat to be sent immediately, and adjust the address's maximum - * number of retransmissions sent before an address is considered - * unreachable. The following structure is used to access and modify an - * address's parameters: - */ - -struct sctp_paddrparams { - struct sockaddr_storage spp_address; - __u32 spp_hbinterval; - __u16 spp_pathmaxrxt; - sctp_assoc_t spp_assoc_id; -}; - -/* - * 7.2.2 Peer Address Information - * - * Applications can retrieve information about a specific peer address - * of an association, including its reachability state, congestion - * window, and retransmission timer values. This information is - * read-only. The following structure is used to access this - * information: - */ - -struct sctp_paddrinfo { - sctp_assoc_t spinfo_assoc_id; - struct sockaddr_storage spinfo_address; - __s32 spinfo_state; - __u32 spinfo_cwnd; - __u32 spinfo_srtt; - __u32 spinfo_rto; - __u32 spinfo_mtu; -}; - - -/* * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) * * The protocol parameters used to initialize and bound retransmission * timeout (RTO) are tunable. See [SCTP] for more information on how - * these parameters are used in RTO calculation. The peer address - * parameter is ignored for TCP style socket. + * these parameters are used in RTO calculation. */ - struct sctp_rtoinfo { + sctp_assoc_t srto_assoc_id; __u32 srto_initial; __u32 srto_max; __u32 srto_min; - sctp_assoc_t srto_assoc_id; }; /* - * 7.1.2 Association Retransmission Parameter (SCTP_ASSOCRTXINFO) + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) * - * The protocol parameter used to set the number of retransmissions - * sent before an association is considered unreachable. - * See [SCTP] for more information on how this parameter is used. The - * peer address parameter is ignored for TCP style socket. + * This option is used to both examine and set various association and + * endpoint parameters. */ - struct sctp_assocparams { - __u16 sasoc_asocmaxrxt; sctp_assoc_t sasoc_assoc_id; + __u16 sasoc_asocmaxrxt; + __u16 sasoc_number_peer_destinations; + __u32 sasoc_peer_rwnd; + __u32 sasoc_local_rwnd; + __u32 sasoc_cookie_life; }; - /* - * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) * * Requests that the peer mark the enclosed address as the association * primary. The enclosed address must be one of the association's * locally bound addresses. The following structure is used to make a * set primary request: */ - -struct sctp_setprim { - struct sockaddr_storage ssp_addr; - sctp_assoc_t ssp_assoc_id; +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; }; /* - * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. The following structure is used to * make a set peer primary request: */ +struct sctp_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +}; -struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; +/* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaption { + __u32 ssb_adaption_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ +struct sctp_paddrparams { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +}; + +/* Peer addresses's state. */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_ACTIVE, }; /* @@ -562,40 +550,16 @@ struct sctp_paddrinfo sstat_primary; }; - /* - * 7.1.12 Set Adaption Layer Indicator - * - * Requests that the local endpoint set the specified Adaption Layer - * Indication parameter for all future - * INIT and INIT-ACK exchanges. - */ - -struct sctp_setadaption { - __u32 ssb_adaption_ind; -}; - -/* - * 7.1.12 Set default message time outs (SCTP_SET_STREAM_TIMEOUTS) - * - * This option requests that the requested stream apply a - * default time-out for messages in queue. - */ -struct sctp_setstrm_timeout { - sctp_assoc_t ssto_assoc_id; - __u32 ssto_timeout; - __u16 ssto_streamid_start; - __u16 ssto_streamid_end; -}; - -/* - * 8.3 8.5 get all peer/local addresses on a socket - * This parameter struct is for getsockopt + * 8.3, 8.5 get all peer/local addresses in an association. + * This parameter struct is used by SCTP_GET_PEER_ADDRS and + * SCTP_GET_LOCAL_ADDRS socket options used internally to implement + * sctp_getpaddrs() and sctp_getladdrs() API. */ struct sctp_getaddrs { sctp_assoc_t assoc_id; int addr_num; - struct sockaddr_storage *addrs; + struct sockaddr *addrs; }; /* These are bit fields for msghdr->msg_flags. See section 5.1. */ @@ -611,8 +575,8 @@ * The flags parameter is formed from the bitwise OR of zero or more of the * following currently defined flags: */ -#define BINDX_ADD_ADDR 0x01 -#define BINDX_REM_ADDR 0x02 +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 /* This is the structure that is passed as an argument(optval) to * getsockopt(SCTP_SOCKOPT_PEELOFF). @@ -623,6 +587,3 @@ } sctp_peeloff_arg_t; #endif /* __net_sctp_user_h__ */ - - - diff -urN linux-2.4.25/include/net/sock.h linux-2.4.26/include/net/sock.h --- linux-2.4.25/include/net/sock.h 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/include/net/sock.h 2004-04-14 06:05:40.000000000 -0700 @@ -432,6 +432,19 @@ __u32 frto_highmark; /* snd_nxt when RTO occurred */ unsigned long last_synq_overflow; + +/* TCP Westwood structure */ + struct { + __u32 bw_ns_est; /* first bandwidth estimation..not too smoothed 8) */ + __u32 bw_est; /* bandwidth estimate */ + __u32 rtt_win_sx; /* here starts a new evaluation... */ + __u32 bk; + __u32 snd_una; /* used for evaluating the number of acked bytes */ + __u32 cumul_ack; + __u32 accounted; + __u32 rtt; + __u32 rtt_min; /* minimum observed RTT */ + } westwood; }; diff -urN linux-2.4.25/include/net/tcp.h linux-2.4.26/include/net/tcp.h --- linux-2.4.25/include/net/tcp.h 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/include/net/tcp.h 2004-04-14 06:05:40.000000000 -0700 @@ -463,6 +463,7 @@ extern int sysctl_tcp_tw_reuse; extern int sysctl_tcp_frto; extern int sysctl_tcp_low_latency; +extern int sysctl_tcp_westwood; extern atomic_t tcp_memory_allocated; extern atomic_t tcp_sockets_allocated; @@ -1863,4 +1864,121 @@ TCP_ADD_STATS_USER(TcpMaxConn, -1); } + +/* TCP Westwood functions and constants */ + +#define TCP_WESTWOOD_INIT_RTT 20*HZ /* maybe too conservative?! */ +#define TCP_WESTWOOD_RTT_MIN HZ/20 /* 50ms */ + +static inline void tcp_westwood_update_rtt(struct tcp_opt *tp, __u32 rtt_seq) +{ + if (sysctl_tcp_westwood) + tp->westwood.rtt = rtt_seq; +} + +void __tcp_westwood_fast_bw(struct sock *, struct sk_buff *); +void __tcp_westwood_slow_bw(struct sock *, struct sk_buff *); + +/* + * This function initializes fields used in TCP Westwood+. We can't + * get no information about RTTmin at this time so we simply set it to + * TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative + * since in this way we're sure it will be updated in a consistent + * way as soon as possible. It will reasonably happen within the first + * RTT period of the connection lifetime. + */ + +static inline void __tcp_init_westwood(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + tp->westwood.bw_ns_est = 0; + tp->westwood.bw_est = 0; + tp->westwood.accounted = 0; + tp->westwood.cumul_ack = 0; + tp->westwood.rtt_win_sx = tcp_time_stamp; + tp->westwood.rtt = TCP_WESTWOOD_INIT_RTT; + tp->westwood.rtt_min = TCP_WESTWOOD_INIT_RTT; + tp->westwood.snd_una = tp->snd_una; +} + +static inline void tcp_init_westwood(struct sock *sk) +{ + __tcp_init_westwood(sk); +} + +static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb) +{ + if (sysctl_tcp_westwood) + __tcp_westwood_fast_bw(sk, skb); +} + +static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb) +{ + if (sysctl_tcp_westwood) + __tcp_westwood_slow_bw(sk, skb); +} + +static inline __u32 __tcp_westwood_bw_rttmin(struct tcp_opt *tp) +{ + return (__u32) ((tp->westwood.bw_est) * (tp->westwood.rtt_min) / + (__u32) (tp->mss_cache)); +} + +static inline __u32 tcp_westwood_bw_rttmin(struct tcp_opt *tp) +{ + __u32 ret = 0; + + if (sysctl_tcp_westwood) + ret = (__u32) (max(__tcp_westwood_bw_rttmin(tp), 2U)); + + return ret; +} + +static inline int tcp_westwood_ssthresh(struct tcp_opt *tp) +{ + int ret = 0; + __u32 ssthresh; + + if (sysctl_tcp_westwood) { + if (!(ssthresh = tcp_westwood_bw_rttmin(tp))) + return ret; + + tp->snd_ssthresh = ssthresh; + ret = 1; + } + + return ret; +} + +static inline int tcp_westwood_cwnd(struct tcp_opt *tp) +{ + int ret = 0; + __u32 cwnd; + + if (sysctl_tcp_westwood) { + if (!(cwnd = tcp_westwood_bw_rttmin(tp))) + return ret; + + tp->snd_cwnd = cwnd; + ret = 1; + } + + return ret; +} + +static inline int tcp_westwood_complete_cwr(struct tcp_opt *tp) +{ + int ret = 0; + + if (sysctl_tcp_westwood) { + if (tcp_westwood_cwnd(tp)) { + tp->snd_ssthresh = tp->snd_cwnd; + ret = 1; + } + } + + return ret; +} + #endif /* _TCP_H */ diff -urN linux-2.4.25/kernel/fork.c linux-2.4.26/kernel/fork.c --- linux-2.4.25/kernel/fork.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/kernel/fork.c 2004-04-14 06:05:40.000000000 -0700 @@ -826,6 +826,8 @@ exit_namespace(p); bad_fork_cleanup_mm: exit_mm(p); + if (p->active_mm) + mmdrop(p->active_mm); bad_fork_cleanup_sighand: exit_sighand(p); bad_fork_cleanup_fs: diff -urN linux-2.4.25/lib/Makefile linux-2.4.26/lib/Makefile --- linux-2.4.25/lib/Makefile 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/lib/Makefile 2004-04-14 06:05:40.000000000 -0700 @@ -42,7 +42,7 @@ crc32.o: crc32table.h gen_crc32table: gen_crc32table.c - $(HOSTCC) $(HOSTCCFLAGS) -o $@ $< + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< crc32table.h: gen_crc32table ./$< > $@ diff -urN linux-2.4.25/lib/crc32.c linux-2.4.26/lib/crc32.c --- linux-2.4.25/lib/crc32.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/lib/crc32.c 2004-04-14 06:05:40.000000000 -0700 @@ -1,6 +1,9 @@ -/* +/* * Oct 15, 2000 Matt Domsch * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! + * Code was from the public domain, copyright abandoned. Code was + * subsequently included in the kernel, thus was re-licensed under the + * GNU GPL v2. * * Oct 12, 2000 Matt Domsch * Same crc32 function was used in 5 other places in the kernel. @@ -12,7 +15,9 @@ * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. * fs/jffs2 uses seed 0, doesn't xor with ~0. * fs/partitions/efi.c uses seed ~0, xor's with ~0. - * + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. */ #include @@ -39,16 +44,10 @@ #define attribute(x) #endif -/* - * This code is in the public domain; copyright abandoned. - * Liability for non-performance of this code is limited to the amount - * you paid for it. Since it is distributed for free, your refund will - * be very very small. If it breaks, you get to keep both pieces. - */ MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("Ethernet CRC32 calculations"); -MODULE_LICENSE("GPL and additional rights"); +MODULE_LICENSE("GPL"); #if CRC_LE_BITS == 1 /* diff -urN linux-2.4.25/mm/filemap.c linux-2.4.26/mm/filemap.c --- linux-2.4.25/mm/filemap.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/mm/filemap.c 2004-04-14 06:05:41.000000000 -0700 @@ -1346,7 +1346,7 @@ while (ahead < max_ahead) { unsigned long ra_index = raend + ahead + 1; - if (ra_index > end_index) + if (ra_index >= end_index) break; if (page_cache_read(filp, ra_index) < 0) break; diff -urN linux-2.4.25/mm/mremap.c linux-2.4.26/mm/mremap.c --- linux-2.4.25/mm/mremap.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/mm/mremap.c 2004-04-14 06:05:41.000000000 -0700 @@ -77,12 +77,16 @@ static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr) { int error = 0; - pte_t * src; + pte_t * src, * dst; spin_lock(&mm->page_table_lock); src = get_one_pte(mm, old_addr); - if (src) - error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr)); + if (src) { + dst = alloc_one_pte(mm, new_addr); + src = get_one_pte(mm, old_addr); + if (src) + error = copy_one_pte(mm, src, dst); + } spin_unlock(&mm->page_table_lock); return error; } diff -urN linux-2.4.25/mm/vmalloc.c linux-2.4.26/mm/vmalloc.c --- linux-2.4.25/mm/vmalloc.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/mm/vmalloc.c 2004-04-14 06:05:41.000000000 -0700 @@ -159,8 +159,8 @@ struct page ***pages) { pgd_t * dir; + unsigned long start = address; unsigned long end = address + size; - int ret; dir = pgd_offset_k(address); spin_lock(&init_mm.page_table_lock); @@ -168,22 +168,24 @@ pmd_t *pmd; pmd = pmd_alloc(&init_mm, dir, address); - ret = -ENOMEM; if (!pmd) - break; + goto err; - ret = -ENOMEM; if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) - break; + goto err; // The kernel NEVER reclaims pmds, so no need to undo pmd_alloc() here address = (address + PGDIR_SIZE) & PGDIR_MASK; dir++; - - ret = 0; } while (address && (address < end)); spin_unlock(&init_mm.page_table_lock); flush_cache_all(); - return ret; + return 0; +err: + spin_unlock(&init_mm.page_table_lock); + flush_cache_all(); + if (address > start) + vmfree_area_pages(start, address - start); + return -ENOMEM; } int vmalloc_area_pages(unsigned long address, unsigned long size, @@ -234,7 +236,7 @@ return NULL; } -void vfree(void * addr) +void __vfree(void * addr, int free_area_pages) { struct vm_struct **p, *tmp; @@ -248,7 +250,8 @@ for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; - vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); + if (free_area_pages) + vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size); write_unlock(&vmlist_lock); kfree(tmp); return; @@ -258,6 +261,11 @@ printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr); } +void vfree(void * addr) +{ + __vfree(addr,1); +} + void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot) { void * addr; @@ -272,7 +280,7 @@ addr = area->addr; if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot, NULL)) { - vfree(addr); + __vfree(addr, 0); return NULL; } return addr; @@ -294,7 +302,7 @@ addr = area->addr; if (__vmalloc_area_pages(VMALLOC_VMADDR(addr), size, 0, prot, &pages)) { - vfree(addr); + __vfree(addr, 0); return NULL; } return addr; diff -urN linux-2.4.25/net/8021q/vlan_dev.c linux-2.4.26/net/8021q/vlan_dev.c --- linux-2.4.25/net/8021q/vlan_dev.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/8021q/vlan_dev.c 2004-04-14 06:05:41.000000000 -0700 @@ -446,6 +446,7 @@ */ if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { + int orig_headroom = skb_headroom(skb); unsigned short veth_TCI; /* This is not a VLAN frame...but we can fix that! */ @@ -455,33 +456,7 @@ printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n", __FUNCTION__, htons(veth->h_vlan_proto)); #endif - - if (skb_headroom(skb) < VLAN_HLEN) { - struct sk_buff *sk_tmp = skb; - skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN); - kfree_skb(sk_tmp); - if (skb == NULL) { - stats->tx_dropped++; - return 0; - } - VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++; - } else { - if (!(skb = skb_unshare(skb, GFP_ATOMIC))) { - printk(KERN_ERR "vlan: failed to unshare skbuff\n"); - stats->tx_dropped++; - return 0; - } - } - veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); - - /* Move the mac addresses to the beginning of the new header. */ - memmove(skb->data, skb->data + VLAN_HLEN, 12); - - /* first, the ethernet type */ - /* put_unaligned(__constant_htons(ETH_P_8021Q), &veth->h_vlan_proto); */ - veth->h_vlan_proto = __constant_htons(ETH_P_8021Q); - - /* Now, construct the second two bytes. This field looks something + /* Construct the second two bytes. This field looks something * like: * usr_priority: 3 bits (high bits) * CFI 1 bit @@ -490,10 +465,16 @@ veth_TCI = VLAN_DEV_INFO(dev)->vlan_id; veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); - veth->h_vlan_TCI = htons(veth_TCI); - } + skb = __vlan_put_tag(skb, veth_TCI); + if (!skb) { + stats->tx_dropped++; + return 0; + } - skb->dev = VLAN_DEV_INFO(dev)->real_dev; + if (orig_headroom < VLAN_HLEN) { + VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++; + } + } #ifdef VLAN_DEBUG printk(VLAN_DBG "%s: about to send skb: %p to dev: %s\n", @@ -507,6 +488,7 @@ stats->tx_packets++; /* for statics only */ stats->tx_bytes += skb->len; + skb->dev = VLAN_DEV_INFO(dev)->real_dev; dev_queue_xmit(skb); return 0; @@ -515,17 +497,22 @@ int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = vlan_dev_get_stats(dev); - struct vlan_skb_tx_cookie *cookie; + unsigned short veth_TCI; + + /* Construct the second two bytes. This field looks something + * like: + * usr_priority: 3 bits (high bits) + * CFI 1 bit + * VLAN ID 12 bits (low bits) + */ + veth_TCI = VLAN_DEV_INFO(dev)->vlan_id; + veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); + skb = __vlan_hwaccel_put_tag(skb, veth_TCI); stats->tx_packets++; stats->tx_bytes += skb->len; skb->dev = VLAN_DEV_INFO(dev)->real_dev; - cookie = VLAN_TX_SKB_CB(skb); - cookie->magic = VLAN_TX_COOKIE_MAGIC; - cookie->vlan_tag = (VLAN_DEV_INFO(dev)->vlan_id | - vlan_dev_get_egress_qos_mask(dev, skb)); - dev_queue_xmit(skb); return 0; diff -urN linux-2.4.25/net/Makefile linux-2.4.26/net/Makefile --- linux-2.4.25/net/Makefile 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/Makefile 2004-04-14 06:05:41.000000000 -0700 @@ -15,10 +15,10 @@ subdir-$(CONFIG_NET) += 802 sched netlink +subdir-$(CONFIG_IPV6) += ipv6 subdir-$(CONFIG_INET) += ipv4 subdir-$(CONFIG_NETFILTER) += ipv4/netfilter subdir-$(CONFIG_UNIX) += unix -subdir-$(CONFIG_IPV6) += ipv6 subdir-$(CONFIG_IP_SCTP) += sctp ifneq ($(CONFIG_IPV6),n) diff -urN linux-2.4.25/net/atm/lec.c linux-2.4.26/net/atm/lec.c --- linux-2.4.25/net/atm/lec.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/atm/lec.c 2004-04-14 06:05:41.000000000 -0700 @@ -208,6 +208,22 @@ return 0; } +static __inline__ void +lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv) +{ + if (atm_may_send(vcc, skb->len)) { + atomic_add(skb->truesize, &vcc->sk->wmem_alloc); + ATM_SKB(skb)->vcc = vcc; + ATM_SKB(skb)->atm_options = vcc->atm_options; + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + vcc->send(vcc, skb); + } else { + priv->stats.tx_dropped++; + dev_kfree_skb(skb); + } +} + static int lec_send_packet(struct sk_buff *skb, struct net_device *dev) { @@ -352,33 +368,10 @@ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); - ATM_SKB(skb2)->vcc = send_vcc; - ATM_SKB(skb2)->atm_options = send_vcc->atm_options; - DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name, - send_vcc->vpi, send_vcc->vci); - if (atm_may_send(send_vcc, skb2->len)) { - atomic_add(skb2->truesize, &send_vcc->sk->wmem_alloc); - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb2->len; - send_vcc->send(send_vcc, skb2); - } else { - priv->stats.tx_dropped++; - dev_kfree_skb(skb2); - } + lec_send(send_vcc, skb2, priv); } - ATM_SKB(skb)->vcc = send_vcc; - ATM_SKB(skb)->atm_options = send_vcc->atm_options; - if (atm_may_send(send_vcc, skb->len)) { - atomic_add(skb->truesize, &send_vcc->sk->wmem_alloc); - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; - send_vcc->send(send_vcc, skb); - } else { - priv->stats.tx_dropped++; - dev_kfree_skb(skb); - } - + lec_send(send_vcc, skb, priv); #if 0 /* Should we wait for card's device driver to notify us? */ dev->tbusy=0; @@ -753,8 +746,8 @@ return -EINVAL; lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, &ioc_data, vcc, vcc->push); - vcc->push = lec_push; vcc->proto_data = dev_lec[ioc_data.dev_num]; + vcc->push = lec_push; return 0; } @@ -1043,7 +1036,7 @@ #define LEC_ARP_REFRESH_INTERVAL (3*HZ) static void lec_arp_check_expire(unsigned long data); -static __inline__ void lec_arp_expire_arp(unsigned long data); +static void lec_arp_expire_arp(unsigned long data); void dump_arp_table(struct lec_priv *priv); /* @@ -1383,7 +1376,7 @@ struct lec_arp_table *entry, *next; int i; - del_timer(&priv->lec_arp_timer); + del_timer_sync(&priv->lec_arp_timer); /* * Remove all entries @@ -1398,7 +1391,7 @@ entry = priv->lec_arp_empty_ones; while(entry) { next = entry->next; - del_timer(&entry->timer); + del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1407,7 +1400,7 @@ entry = priv->lec_no_forward; while(entry) { next = entry->next; - del_timer(&entry->timer); + del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1416,7 +1409,7 @@ entry = priv->mcast_fwds; while(entry) { next = entry->next; - del_timer(&entry->timer); + /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1490,8 +1483,6 @@ entry = (struct lec_arp_table *)data; - del_timer(&entry->timer); - DPRINTK("lec_arp_expire_arp\n"); if (entry->status == ESI_ARP_PENDING) { if (entry->no_tries <= entry->priv->max_retry_count) { @@ -1501,8 +1492,7 @@ send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL); entry->no_tries++; } - entry->timer.expires = jiffies + (1*HZ); - add_timer(&entry->timer); + mod_timer(&entry->timer, jiffies + (1*HZ)); } } @@ -1574,8 +1564,6 @@ unsigned long time_to_check; int i; - del_timer(&priv->lec_arp_timer); - DPRINTK("lec_arp_check_expire %p,%d\n",priv, atomic_read(&priv->lec_arp_users)); DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, @@ -1619,6 +1607,10 @@ && time_after_eq(now, entry->timestamp+ priv->path_switching_delay)) { + struct sk_buff *skb; + + while ((skb = skb_dequeue(&entry->tx_wait))) + lec_send(entry->vcc, skb, entry->priv); entry->last_used = jiffies; entry->status = ESI_FORWARD_DIRECT; @@ -1629,8 +1621,8 @@ } lec_arp_put(priv); } - priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; - add_timer(&priv->lec_arp_timer); + + mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL); } /* * Try to find vcc where mac_address is attached. @@ -2012,6 +2004,10 @@ for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) { if (entry->flush_tran_id == tran_id && entry->status == ESI_FLUSH_PENDING) { + struct sk_buff *skb; + + while ((skb = skb_dequeue(&entry->tx_wait))) + lec_send(entry->vcc, skb, entry->priv); entry->status = ESI_FORWARD_DIRECT; DPRINTK("LEC_ARP: Flushed\n"); } diff -urN linux-2.4.25/net/atm/mpoa_proc.c linux-2.4.26/net/atm/mpoa_proc.c --- linux-2.4.25/net/atm/mpoa_proc.c 2001-07-04 11:50:38.000000000 -0700 +++ linux-2.4.26/net/atm/mpoa_proc.c 2004-04-14 06:05:41.000000000 -0700 @@ -102,7 +102,7 @@ size_t count, loff_t *pos){ unsigned long page = 0; unsigned char *temp; - ssize_t length = 0; + int length = 0; int i = 0; struct mpoa_client *mpc = mpcs; in_cache_entry *in_entry; diff -urN linux-2.4.25/net/bluetooth/af_bluetooth.c linux-2.4.26/net/bluetooth/af_bluetooth.c --- linux-2.4.25/net/bluetooth/af_bluetooth.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/bluetooth/af_bluetooth.c 2004-04-14 06:05:41.000000000 -0700 @@ -221,12 +221,11 @@ unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; - unsigned int mask; + unsigned int mask = 0; BT_DBG("sock %p, sk %p", sock, sk); poll_wait(file, sk->sleep, wait); - mask = 0; if (sk->err || !skb_queue_empty(&sk->error_queue)) mask |= POLLERR; @@ -242,9 +241,11 @@ if (sk->state == BT_CLOSED) mask |= POLLHUP; - if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2) + if (sk->state == BT_CONNECT || + sk->state == BT_CONNECT2 || + sk->state == BT_CONFIG) return mask; - + if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else diff -urN linux-2.4.25/net/bluetooth/bnep/sock.c linux-2.4.26/net/bluetooth/bnep/sock.c --- linux-2.4.25/net/bluetooth/bnep/sock.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/bluetooth/bnep/sock.c 2004-04-14 06:05:41.000000000 -0700 @@ -94,8 +94,10 @@ if (!nsock) return err; - if (nsock->sk->state != BT_CONNECTED) + if (nsock->sk->state != BT_CONNECTED) { + fput(nsock->file); return -EBADFD; + } err = bnep_add_connection(&ca, nsock); if (!err) { diff -urN linux-2.4.25/net/bluetooth/cmtp/sock.c linux-2.4.26/net/bluetooth/cmtp/sock.c --- linux-2.4.25/net/bluetooth/cmtp/sock.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/bluetooth/cmtp/sock.c 2004-04-14 06:05:41.000000000 -0700 @@ -86,8 +86,10 @@ if (!nsock) return err; - if (nsock->sk->state != BT_CONNECTED) + if (nsock->sk->state != BT_CONNECTED) { + fput(nsock->file); return -EBADFD; + } err = cmtp_add_connection(&ca, nsock); if (!err) { diff -urN linux-2.4.25/net/bluetooth/hci_conn.c linux-2.4.26/net/bluetooth/hci_conn.c --- linux-2.4.25/net/bluetooth/hci_conn.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/bluetooth/hci_conn.c 2004-04-14 06:05:41.000000000 -0700 @@ -358,21 +358,24 @@ struct hci_conn_info *ci; struct hci_dev *hdev; struct list_head *p; - int n = 0, size; + int n = 0, size, err; if (copy_from_user(&req, (void *) arg, sizeof(req))) return -EFAULT; - if (!(hdev = hci_dev_get(req.dev_id))) - return -ENODEV; - - size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); + if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci)) + return -EINVAL; - if (verify_area(VERIFY_WRITE, (void *)arg, size)) - return -EFAULT; + size = sizeof(req) + req.conn_num * sizeof(*ci); if (!(cl = (void *) kmalloc(size, GFP_KERNEL))) return -ENOMEM; + + if (!(hdev = hci_dev_get(req.dev_id))) { + kfree(cl); + return -ENODEV; + } + ci = cl->conn_info; hci_dev_lock_bh(hdev); @@ -386,20 +389,21 @@ (ci + n)->out = c->out; (ci + n)->state = c->state; (ci + n)->link_mode = c->link_mode; - n++; + if (++n >= req.conn_num) + break; } hci_dev_unlock_bh(hdev); cl->dev_id = hdev->id; cl->conn_num = n; - size = n * sizeof(struct hci_conn_info) + sizeof(req); + size = sizeof(req) + n * sizeof(*ci); hci_dev_put(hdev); - copy_to_user((void *) arg, cl, size); + err = copy_to_user((void *) arg, cl, size); kfree(cl); - return 0; + return err ? -EFAULT : 0; } int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) @@ -412,9 +416,6 @@ if (copy_from_user(&req, (void *) arg, sizeof(req))) return -EFAULT; - if (verify_area(VERIFY_WRITE, ptr, sizeof(ci))) - return -EFAULT; - hci_dev_lock_bh(hdev); conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); if (conn) { @@ -430,6 +431,5 @@ if (!conn) return -ENOENT; - copy_to_user(ptr, &ci, sizeof(ci)); - return 0; + return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0; } diff -urN linux-2.4.25/net/bluetooth/hci_core.c linux-2.4.26/net/bluetooth/hci_core.c --- linux-2.4.25/net/bluetooth/hci_core.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/bluetooth/hci_core.c 2004-04-14 06:05:41.000000000 -0700 @@ -218,6 +218,10 @@ /* Mandatory initialization */ + /* Reset */ + if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks)) + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); + /* Read Local Supported Features */ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL); @@ -712,22 +716,20 @@ struct hci_dev_list_req *dl; struct hci_dev_req *dr; struct list_head *p; - int n = 0, size; + int n = 0, size, err; __u16 dev_num; if (get_user(dev_num, (__u16 *) arg)) return -EFAULT; - if (!dev_num) + if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr)) return -EINVAL; - - size = dev_num * sizeof(*dr) + sizeof(*dl); - if (verify_area(VERIFY_WRITE, (void *) arg, size)) - return -EFAULT; + size = sizeof(*dl) + dev_num * sizeof(*dr); if (!(dl = kmalloc(size, GFP_KERNEL))) return -ENOMEM; + dr = dl->dev_req; read_lock_bh(&hdev_list_lock); @@ -742,12 +744,12 @@ read_unlock_bh(&hdev_list_lock); dl->dev_num = n; - size = n * sizeof(*dr) + sizeof(*dl); + size = sizeof(*dl) + n * sizeof(*dr); - copy_to_user((void *) arg, dl, size); + err = copy_to_user((void *) arg, dl, size); kfree(dl); - return 0; + return err ? -EFAULT : 0; } int hci_get_dev_info(unsigned long arg) diff -urN linux-2.4.25/net/bluetooth/l2cap.c linux-2.4.26/net/bluetooth/l2cap.c --- linux-2.4.25/net/bluetooth/l2cap.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/bluetooth/l2cap.c 2004-04-14 06:05:41.000000000 -0700 @@ -1649,6 +1649,8 @@ l2cap_cmd_hdr cmd; int err = 0; + l2cap_raw_recv(conn, skb); + while (len >= L2CAP_CMD_HDR_SIZE) { memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); data += L2CAP_CMD_HDR_SIZE; @@ -1690,7 +1692,6 @@ case L2CAP_COMMAND_REJ: /* FIXME: We should process this */ - l2cap_raw_recv(conn, skb); break; case L2CAP_ECHO_REQ: @@ -1700,11 +1701,10 @@ case L2CAP_ECHO_RSP: case L2CAP_INFO_REQ: case L2CAP_INFO_RSP: - l2cap_raw_recv(conn, skb); break; default: - BT_ERR("Uknown signaling command 0x%2.2x", cmd.code); + BT_ERR("Unknown signaling command 0x%2.2x", cmd.code); err = -EINVAL; break; }; diff -urN linux-2.4.25/net/bluetooth/rfcomm/core.c linux-2.4.26/net/bluetooth/rfcomm/core.c --- linux-2.4.25/net/bluetooth/rfcomm/core.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/bluetooth/rfcomm/core.c 2004-04-14 06:05:41.000000000 -0700 @@ -1654,9 +1654,10 @@ nsock->sk->state_change = rfcomm_l2state_change; s = rfcomm_session_add(nsock, BT_OPEN); - if (s) + if (s) { rfcomm_session_hold(s); - else + rfcomm_schedule(RFCOMM_SCHED_RX); + } else sock_release(nsock); } diff -urN linux-2.4.25/net/bluetooth/rfcomm/tty.c linux-2.4.26/net/bluetooth/rfcomm/tty.c --- linux-2.4.25/net/bluetooth/rfcomm/tty.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/bluetooth/rfcomm/tty.c 2004-04-14 06:05:41.000000000 -0700 @@ -109,6 +109,13 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev) { + /* The reason this isn't actually a race, as you no + doubt have a little voice screaming at you in your + head, is that the refcount should never actually + reach zero unless the device has already been taken + off the list, in rfcomm_dev_del(). And if that's not + true, we'll hit the BUG() in rfcomm_dev_destruct() + anyway. */ if (atomic_dec_and_test(&dev->refcnt)) rfcomm_dev_destruct(dev); } @@ -132,10 +139,13 @@ struct rfcomm_dev *dev; read_lock(&rfcomm_dev_lock); + dev = __rfcomm_dev_get(id); + if (dev) + rfcomm_dev_hold(dev); + read_unlock(&rfcomm_dev_lock); - if (dev) rfcomm_dev_hold(dev); return dev; } @@ -347,7 +357,7 @@ struct rfcomm_dev_list_req *dl; struct rfcomm_dev_info *di; struct list_head *p; - int n = 0, size; + int n = 0, size, err; u16 dev_num; BT_DBG(""); @@ -355,14 +365,11 @@ if (get_user(dev_num, (u16 *) arg)) return -EFAULT; - if (!dev_num) + if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di)) return -EINVAL; size = sizeof(*dl) + dev_num * sizeof(*di); - if (verify_area(VERIFY_WRITE, (void *)arg, size)) - return -EFAULT; - if (!(dl = kmalloc(size, GFP_KERNEL))) return -ENOMEM; @@ -387,9 +394,10 @@ dl->dev_num = n; size = sizeof(*dl) + n * sizeof(*di); - copy_to_user((void *) arg, dl, size); + err = copy_to_user((void *) arg, dl, size); kfree(dl); - return 0; + + return err ? -EFAULT : 0; } static int rfcomm_get_dev_info(unsigned long arg) @@ -486,7 +494,8 @@ rfcomm_dev_del(dev); /* We have to drop DLC lock here, otherwise - * rfcomm_dev_put() will dead lock if it's the last refference */ + rfcomm_dev_put() will dead lock if it's + the last reference. */ rfcomm_dlc_unlock(dlc); rfcomm_dev_put(dev); rfcomm_dlc_lock(dlc); @@ -541,6 +550,10 @@ BT_DBG("tty %p id %d", tty, id); + /* We don't leak this refcount. For reasons which are not entirely + clear, the TTY layer will call our ->close() method even if the + open fails. We decrease the refcount there, and decreasing it + here too would cause breakage. */ dev = rfcomm_dev_get(id); if (!dev) return -ENODEV; diff -urN linux-2.4.25/net/core/dev.c linux-2.4.26/net/core/dev.c --- linux-2.4.25/net/core/dev.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/core/dev.c 2004-04-14 06:05:41.000000000 -0700 @@ -1462,7 +1462,7 @@ { struct packet_type *ptype, *pt_prev; int ret = NET_RX_DROP; - unsigned short type = skb->protocol; + unsigned short type; if (skb->stamp.tv_sec == 0) do_gettimeofday(&skb->stamp); @@ -1507,6 +1507,7 @@ } #endif + type = skb->protocol; for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { diff -urN linux-2.4.25/net/core/sock.c linux-2.4.26/net/core/sock.c --- linux-2.4.25/net/core/sock.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.26/net/core/sock.c 2004-04-14 06:05:41.000000000 -0700 @@ -128,6 +128,16 @@ #include #endif +/* Take into consideration the size of the struct sk_buff overhead in the + * determination of these values, since that is non-constant across + * platforms. This makes socket queueing behavior and performance + * not depend upon such differences. + */ +#define _SK_MEM_PACKETS 256 +#define _SK_MEM_OVERHEAD (sizeof(struct sk_buff) + 256) +#define SK_WMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) +#define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) + /* Run time adjustable parameters. */ __u32 sysctl_wmem_max = SK_WMEM_MAX; __u32 sysctl_rmem_max = SK_RMEM_MAX; diff -urN linux-2.4.25/net/ipv4/arp.c linux-2.4.26/net/ipv4/arp.c --- linux-2.4.25/net/ipv4/arp.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/arp.c 2004-04-14 06:05:41.000000000 -0700 @@ -66,6 +66,10 @@ * Alexey Kuznetsov: new arp state machine; * now it is in net/core/neighbour.c. * Krzysztof Halasa: Added Frame Relay ARP support. + * Shmulik Hen: Split arp_send to arp_create and + * arp_xmit so intermediate drivers like + * bonding can change the skb before + * sending (e.g. insert 8021q tag). */ #include @@ -317,15 +321,40 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) { - u32 saddr; + u32 saddr = 0; u8 *dst_ha = NULL; struct net_device *dev = neigh->dev; u32 target = *(u32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); + struct in_device *in_dev = in_dev_get(dev); + + if (!in_dev) + return; - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) + switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { + default: + case 0: /* By default announce any local IP */ + if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) + saddr = skb->nh.iph->saddr; + break; + case 1: /* Restrict announcements of saddr in same subnet */ + if (!skb) + break; saddr = skb->nh.iph->saddr; - else + if (inet_addr_type(saddr) == RTN_LOCAL) { + /* saddr should be known to target */ + if (inet_addr_onlink(in_dev, target, saddr)) + break; + } + saddr = 0; + break; + case 2: /* Avoid secondary IPs, get a primary/preferred one */ + break; + } + + if (in_dev) + in_dev_put(in_dev); + if (!saddr) saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -346,6 +375,42 @@ read_unlock_bh(&neigh->lock); } +static int arp_ignore(struct in_device *in_dev, struct net_device *dev, + u32 sip, u32 tip) +{ + int scope; + + switch (IN_DEV_ARP_IGNORE(in_dev)) { + case 0: /* Reply, the tip is already validated */ + return 0; + case 1: /* Reply only if tip is configured on the incoming interface */ + sip = 0; + scope = RT_SCOPE_HOST; + break; + case 2: /* + * Reply only if tip is configured on the incoming interface + * and is in same subnet as sip + */ + scope = RT_SCOPE_HOST; + break; + case 3: /* Do not reply for scope host addresses */ + sip = 0; + scope = RT_SCOPE_LINK; + dev = NULL; + break; + case 4: /* Reserved */ + case 5: + case 6: + case 7: + return 0; + case 8: /* Do not reply */ + return 1; + default: + return 0; + } + return !inet_confirm_addr(dev, sip, tip, scope); +} + static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) { struct rtable *rt; @@ -481,34 +546,26 @@ */ /* - * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast + * Create an arp packet. If (dest_hw == NULL), we create a broadcast * message. */ - -void arp_send(int type, int ptype, u32 dest_ip, - struct net_device *dev, u32 src_ip, - unsigned char *dest_hw, unsigned char *src_hw, - unsigned char *target_hw) +struct sk_buff *arp_create(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw) { struct sk_buff *skb; struct arphdr *arp; unsigned char *arp_ptr; /* - * No arp on this interface. - */ - - if (dev->flags&IFF_NOARP) - return; - - /* * Allocate a buffer */ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + dev->hard_header_len + 15, GFP_ATOMIC); if (skb == NULL) - return; + return NULL; skb_reserve(skb, (dev->hard_header_len+15)&~15); skb->nh.raw = skb->data; @@ -588,12 +645,46 @@ arp_ptr+=dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); - /* Send it off, maybe filter it using firewalling first. */ - NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit); - return; + return skb; out: kfree_skb(skb); + return NULL; +} + +/* + * Send an arp packet. + */ +void arp_xmit(struct sk_buff *skb) +{ + /* Send it off, maybe filter it using firewalling first. */ + NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit); +} + +/* + * Create and send an arp packet. + */ +void arp_send(int type, int ptype, u32 dest_ip, + struct net_device *dev, u32 src_ip, + unsigned char *dest_hw, unsigned char *src_hw, + unsigned char *target_hw) +{ + struct sk_buff *skb; + + /* + * No arp on this interface. + */ + + if (dev->flags&IFF_NOARP) + return; + + skb = arp_create(type, ptype, dest_ip, dev, src_ip, + dest_hw, src_hw, target_hw); + if (skb == NULL) { + return; + } + + arp_xmit(skb); } static void parp_redo(struct sk_buff *skb) @@ -756,7 +847,8 @@ /* Special case: IPv4 duplicate address detection packet (RFC2131) */ if (sip == 0) { if (arp->ar_op == htons(ARPOP_REQUEST) && - inet_addr_type(tip) == RTN_LOCAL) + inet_addr_type(tip) == RTN_LOCAL && + !arp_ignore(in_dev,dev,sip,tip)) arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr); goto out; } @@ -771,7 +863,10 @@ n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) { int dont_send = 0; - if (IN_DEV_ARPFILTER(in_dev)) + + if (!dont_send) + dont_send |= arp_ignore(in_dev,dev,sip,tip); + if (!dont_send && IN_DEV_ARPFILTER(in_dev)) dont_send |= arp_filter(sip,tip,dev); if (!dont_send) arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); diff -urN linux-2.4.25/net/ipv4/devinet.c linux-2.4.26/net/ipv4/devinet.c --- linux-2.4.25/net/ipv4/devinet.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv4/devinet.c 2004-04-14 06:05:41.000000000 -0700 @@ -151,7 +151,8 @@ #ifdef CONFIG_SYSCTL devinet_sysctl_register(in_dev, &in_dev->cnf); #endif - if (dev->flags&IFF_UP) + ip_mc_init_dev(in_dev); + if (dev->flags & IFF_UP) ip_mc_up(in_dev); return in_dev; } @@ -772,6 +773,84 @@ return 0; } +static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, + u32 local, int scope) +{ + int same = 0; + u32 addr = 0; + + for_ifa(in_dev) { + if (!addr && + (local == ifa->ifa_local || !local) && + ifa->ifa_scope <= scope) { + addr = ifa->ifa_local; + if (same) + break; + } + if (!same) { + same = (!local || inet_ifa_match(local, ifa)) && + (!dst || inet_ifa_match(dst, ifa)); + if (same && addr) { + if (local || !dst) + break; + /* Is the selected addr into dst subnet? */ + if (inet_ifa_match(addr, ifa)) + break; + /* No, then can we use new local src? */ + if (ifa->ifa_scope <= scope) { + addr = ifa->ifa_local; + break; + } + /* search for large dst subnet for addr */ + same = 0; + } + } + } endfor_ifa(in_dev); + + return same? addr : 0; +} + +/* + * Confirm that local IP address exists using wildcards: + * - dev: only on this interface, 0=any interface + * - dst: only in the same subnet as dst, 0=any dst + * - local: address, 0=autoselect the local address + * - scope: maximum allowed scope value for the local address + */ +u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope) +{ + u32 addr = 0; + struct in_device *in_dev; + + if (dev) { + read_lock(&inetdev_lock); + if ((in_dev = __in_dev_get(dev))) { + read_lock(&in_dev->lock); + addr = confirm_addr_indev(in_dev, dst, local, scope); + read_unlock(&in_dev->lock); + } + read_unlock(&inetdev_lock); + + return addr; + } + + read_lock(&dev_base_lock); + read_lock(&inetdev_lock); + for (dev = dev_base; dev; dev = dev->next) { + if ((in_dev = __in_dev_get(dev))) { + read_lock(&in_dev->lock); + addr = confirm_addr_indev(in_dev, dst, local, scope); + read_unlock(&in_dev->lock); + if (addr) + break; + } + } + read_unlock(&inetdev_lock); + read_unlock(&dev_base_lock); + + return addr; +} + /* * Device notifier */ @@ -1012,10 +1091,9 @@ #ifdef CONFIG_SYSCTL -void inet_forward_change() +void inet_forward_change(int on) { struct net_device *dev; - int on = ipv4_devconf.forwarding; ipv4_devconf.accept_redirects = !on; ipv4_devconf_dflt.forwarding = on; @@ -1046,7 +1124,7 @@ if (write && *valp != val) { if (valp == &ipv4_devconf.forwarding) - inet_forward_change(); + inet_forward_change(*valp); else if (valp != &ipv4_devconf_dflt.forwarding) rt_cache_flush(0); } @@ -1057,7 +1135,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[18]; + ctl_table devinet_vars[20]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1106,6 +1184,12 @@ {NET_IPV4_CONF_ARPFILTER, "arp_filter", &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV4_CONF_ARP_ANNOUNCE, "arp_announce", + &ipv4_devconf.arp_announce, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_CONF_ARP_IGNORE, "arp_ignore", + &ipv4_devconf.arp_ignore, sizeof(int), 0644, NULL, + &proc_dointvec}, {NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version", &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL, &proc_dointvec}, diff -urN linux-2.4.25/net/ipv4/icmp.c linux-2.4.26/net/ipv4/icmp.c --- linux-2.4.25/net/ipv4/icmp.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv4/icmp.c 2004-04-14 06:05:41.000000000 -0700 @@ -984,7 +984,13 @@ panic("Failed to create the ICMP control socket.\n"); icmp_socket_cpu(i)->sk->allocation=GFP_ATOMIC; - icmp_socket_cpu(i)->sk->sndbuf = SK_WMEM_MAX*2; + + /* Enough space for 2 64K ICMP packets, including + * sk_buff struct overhead. + */ + icmp_socket_cpu(i)->sk->sndbuf = + (2 * ((64 * 1024) + sizeof(struct sk_buff))); + icmp_socket_cpu(i)->sk->protinfo.af_inet.ttl = MAXTTL; icmp_socket_cpu(i)->sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT; diff -urN linux-2.4.25/net/ipv4/igmp.c linux-2.4.26/net/ipv4/igmp.c --- linux-2.4.25/net/ipv4/igmp.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv4/igmp.c 2004-04-14 06:05:41.000000000 -0700 @@ -101,7 +101,8 @@ #endif -#define IP_MAX_MEMBERSHIPS 20 +#define IP_MAX_MEMBERSHIPS 20 +#define IP_MAX_MSF 10 #ifdef CONFIG_IP_MULTICAST /* Parameter names and values are taken from igmp-v2-06 draft */ @@ -1204,6 +1205,9 @@ ASSERT_RTNL(); + for (i=in_dev->mc_list; i; i=i->next) + igmp_group_dropped(i); + #ifdef CONFIG_IP_MULTICAST in_dev->mr_ifc_count = 0; if (del_timer(&in_dev->mr_ifc_timer)) @@ -1211,24 +1215,14 @@ in_dev->mr_gq_running = 0; if (del_timer(&in_dev->mr_gq_timer)) __in_dev_put(in_dev); -#endif - - for (i=in_dev->mc_list; i; i=i->next) - igmp_group_dropped(i); - -#ifdef CONFIG_IP_MULTICAST igmpv3_clear_delrec(in_dev); #endif ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS); } -/* Device going up */ - -void ip_mc_up(struct in_device *in_dev) +void ip_mc_init_dev(struct in_device *in_dev) { - struct ip_mc_list *i; - ASSERT_RTNL(); in_dev->mc_tomb = 0; @@ -1245,6 +1239,16 @@ #endif in_dev->mc_lock = RW_LOCK_UNLOCKED; +} + +/* Device going up */ + +void ip_mc_up(struct in_device *in_dev) +{ + struct ip_mc_list *i; + + ASSERT_RTNL(); + ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); for (i=in_dev->mc_list; i; i=i->next) @@ -1311,6 +1315,7 @@ * Join a socket to a group */ int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS; +int sysctl_igmp_max_msf = IP_MAX_MSF; static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, @@ -1772,6 +1777,10 @@ } /* else, add a new source to the filter */ + if (psl && psl->sl_count >= sysctl_igmp_max_msf) { + err = -ENOBUFS; + goto done; + } if (!psl || psl->sl_count == psl->sl_max) { struct ip_sf_socklist *newpsl; int count = IP_SFBLOCK; diff -urN linux-2.4.25/net/ipv4/ip_sockglue.c linux-2.4.26/net/ipv4/ip_sockglue.c --- linux-2.4.25/net/ipv4/ip_sockglue.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/ipv4/ip_sockglue.c 2004-04-14 06:05:41.000000000 -0700 @@ -608,10 +608,16 @@ } case IP_MSFILTER: { + extern int sysctl_optmem_max; + extern int sysctl_igmp_max_msf; struct ip_msfilter *msf; if (optlen < IP_MSFILTER_SIZE(0)) goto e_inval; + if (optlen > sysctl_optmem_max) { + err = -ENOBUFS; + break; + } msf = (struct ip_msfilter *)kmalloc(optlen, GFP_KERNEL); if (msf == 0) { err = -ENOBUFS; @@ -622,6 +628,18 @@ kfree(msf); break; } + /* numsrc >= (1G-4) overflow in 32 bits */ + if (msf->imsf_numsrc >= 0x3ffffffcU || + msf->imsf_numsrc > sysctl_igmp_max_msf) { + kfree(msf); + err = -ENOBUFS; + break; + } + if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) { + kfree(msf); + err = -EINVAL; + break; + } err = ip_mc_msfilter(sk, msf, 0); kfree(msf); break; @@ -744,6 +762,8 @@ } case MCAST_MSFILTER: { + extern int sysctl_optmem_max; + extern int sysctl_igmp_max_msf; struct sockaddr_in *psin; struct ip_msfilter *msf = 0; struct group_filter *gsf = 0; @@ -751,6 +771,10 @@ if (optlen < GROUP_FILTER_SIZE(0)) goto e_inval; + if (optlen > sysctl_optmem_max) { + err = -ENOBUFS; + break; + } gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); if (gsf == 0) { err = -ENOBUFS; @@ -760,7 +784,13 @@ if (copy_from_user(gsf, optval, optlen)) { goto mc_msf_out; } - if (GROUP_FILTER_SIZE(gsf->gf_numsrc) < optlen) { + /* numsrc >= (4G-140)/128 overflow in 32 bits */ + if (gsf->gf_numsrc >= 0x1ffffff || + gsf->gf_numsrc > sysctl_igmp_max_msf) { + err = -ENOBUFS; + goto mc_msf_out; + } + if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { err = EINVAL; goto mc_msf_out; } diff -urN linux-2.4.25/net/ipv4/ipvs/Config.in linux-2.4.26/net/ipv4/ipvs/Config.in --- linux-2.4.25/net/ipv4/ipvs/Config.in 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/Config.in 2004-04-14 06:05:41.000000000 -0700 @@ -11,7 +11,7 @@ comment 'IPVS scheduler' dep_tristate ' round-robin scheduling' CONFIG_IP_VS_RR $CONFIG_IP_VS dep_tristate ' weighted round-robin scheduling' CONFIG_IP_VS_WRR $CONFIG_IP_VS - dep_tristate ' least-connection scheduling scheduling' CONFIG_IP_VS_LC $CONFIG_IP_VS + dep_tristate ' least-connection scheduling' CONFIG_IP_VS_LC $CONFIG_IP_VS dep_tristate ' weighted least-connection scheduling' CONFIG_IP_VS_WLC $CONFIG_IP_VS dep_tristate ' locality-based least-connection scheduling' CONFIG_IP_VS_LBLC $CONFIG_IP_VS dep_tristate ' locality-based least-connection with replication scheduling' CONFIG_IP_VS_LBLCR $CONFIG_IP_VS diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_app.c linux-2.4.26/net/ipv4/ipvs/ip_vs_app.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_app.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_app.c 2004-04-14 06:05:41.000000000 -0700 @@ -20,18 +20,12 @@ * */ -#include #include -#include #include -#include #include #include #include -#include #include -#include -#include #include #include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.26/net/ipv4/ipvs/ip_vs_conn.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_conn.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_conn.c 2004-04-14 06:05:41.000000000 -0700 @@ -24,12 +24,8 @@ * */ -#include #include -#include #include -#include -#include #include #include #include /* for tcphdr */ @@ -141,25 +137,27 @@ static int ip_vs_conn_hash(struct ip_vs_conn *cp) { unsigned hash; - - if (cp->flags & IP_VS_CONN_F_HASHED) { - IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, " - "called from %p\n", __builtin_return_address(0)); - return 0; - } + int ret; /* Hash by protocol, client address and port */ hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport); ct_write_lock(hash); - list_add(&cp->c_list, &ip_vs_conn_tab[hash]); - cp->flags |= IP_VS_CONN_F_HASHED; - atomic_inc(&cp->refcnt); + if (!(cp->flags & IP_VS_CONN_F_HASHED)) { + list_add(&cp->c_list, &ip_vs_conn_tab[hash]); + cp->flags |= IP_VS_CONN_F_HASHED; + atomic_inc(&cp->refcnt); + ret = 1; + } else { + IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, " + "called from %p\n", __builtin_return_address(0)); + ret = 0; + } ct_write_unlock(hash); - return 1; + return ret; } @@ -170,24 +168,23 @@ static int ip_vs_conn_unhash(struct ip_vs_conn *cp) { unsigned hash; - - if (!(cp->flags & IP_VS_CONN_F_HASHED)) { - IP_VS_ERR("ip_vs_conn_unhash(): request for unhash flagged, " - "called from %p\n", __builtin_return_address(0)); - return 0; - } + int ret; /* unhash it and decrease its reference counter */ hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport); ct_write_lock(hash); - list_del(&cp->c_list); - cp->flags &= ~IP_VS_CONN_F_HASHED; - atomic_dec(&cp->refcnt); + if (cp->flags & IP_VS_CONN_F_HASHED) { + list_del(&cp->c_list); + cp->flags &= ~IP_VS_CONN_F_HASHED; + atomic_dec(&cp->refcnt); + ret = 1; + } else + ret = 0; ct_write_unlock(hash); - return 1; + return ret; } @@ -725,15 +722,20 @@ /* * Check if it is no_cport connection ... */ - if (cp->flags & IP_VS_CONN_F_NO_CPORT) { - atomic_dec(&ip_vs_conn_no_cport_cnt); - ip_vs_conn_unhash(cp); - cp->flags &= ~IP_VS_CONN_F_NO_CPORT; - cp->cport = h.portp[0]; - /* hash on new dport */ - ip_vs_conn_hash(cp); + if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) { + if (ip_vs_conn_unhash(cp)) { + spin_lock(&cp->lock); + if (cp->flags & IP_VS_CONN_F_NO_CPORT) { + atomic_dec(&ip_vs_conn_no_cport_cnt); + cp->flags &= ~IP_VS_CONN_F_NO_CPORT; + cp->cport = h.portp[0]; + IP_VS_DBG(10, "filled cport=%d\n", ntohs(cp->dport)); + } + spin_unlock(&cp->lock); - IP_VS_DBG(10, "filled cport=%d\n", ntohs(cp->dport)); + /* hash on new dport */ + ip_vs_conn_hash(cp); + } } if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos)))) @@ -890,8 +892,6 @@ /* update checksum because skb might be defragmented */ ip_send_check(old_iph); - skb->h.raw = skb->nh.raw; - /* * Okay, now see if we can stuff it in the buffer as-is. */ @@ -911,6 +911,7 @@ old_iph = skb->nh.iph; } + skb->h.raw = skb->nh.raw; skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); @@ -1142,11 +1143,14 @@ /* * Invalidate the connection template */ - ip_vs_conn_unhash(ct); - ct->dport = 65535; - ct->vport = 65535; - ct->cport = 0; - ip_vs_conn_hash(ct); + if (ct->cport) { + if (ip_vs_conn_unhash(ct)) { + ct->dport = 65535; + ct->vport = 65535; + ct->cport = 0; + ip_vs_conn_hash(ct); + } + } /* * Simply decrease the refcnt of the template, @@ -1200,7 +1204,8 @@ /* * unhash it if it is hashed in the conn table */ - ip_vs_conn_unhash(cp); + if (!ip_vs_conn_unhash(cp)) + goto expire_later; /* * refcnt==1 implies I'm the only one referrer diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_ctl.c linux-2.4.26/net/ipv4/ipvs/ip_vs_ctl.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_ctl.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_ctl.c 2004-04-14 06:05:41.000000000 -0700 @@ -20,12 +20,9 @@ * */ -#include -#include #include #include #include -#include #include #include #include @@ -892,9 +889,16 @@ __ip_vs_update_dest(svc, dest, ur); + write_lock_bh(&__ip_vs_svc_lock); + + /* Wait until all other svc users go away */ + while (atomic_read(&svc->usecnt) > 1) {}; + /* call the update_service, because server weight may be changed */ svc->scheduler->update_service(svc); + write_unlock_bh(&__ip_vs_svc_lock); + LeaveFunction(2); return 0; @@ -1694,7 +1698,7 @@ * len > 128000 is a sanity check. */ if (len < sizeof(struct ip_vs_rule_user)) { - IP_VS_ERR("set_ctl: len %u < %u\n", + IP_VS_ERR("set_ctl: len %u < %Zu\n", len, sizeof(struct ip_vs_rule_user)); return -EINVAL; } else if (len > 128000) { @@ -1740,9 +1744,9 @@ * Check for valid protocol: TCP or UDP. Even for fwmark!=0 */ if (urule->protocol!=IPPROTO_TCP && urule->protocol!=IPPROTO_UDP) { - IP_VS_INFO("vs_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s", - ntohs(urule->protocol), NIPQUAD(urule->vaddr), - ntohs(urule->vport), urule->sched_name); + IP_VS_ERR("set_ctl: invalid protocol %d %d.%d.%d.%d:%d %s\n", + urule->protocol, NIPQUAD(urule->vaddr), + ntohs(urule->vport), urule->sched_name); ret = -EFAULT; goto out_unlock; } @@ -1972,7 +1976,7 @@ struct ip_vs_get_services get; if (*len < sizeof(get)) { - IP_VS_ERR("length: %u < %u\n", *len, sizeof(get)); + IP_VS_ERR("length: %u < %Zu\n", *len, sizeof(get)); ret = -EINVAL; goto out; } @@ -1981,7 +1985,7 @@ goto out; } if (*len != (sizeof(get)+sizeof(struct ip_vs_service_user)*get.num_services)) { - IP_VS_ERR("length: %u != %u\n", *len, + IP_VS_ERR("length: %u != %Zu\n", *len, sizeof(get)+sizeof(struct ip_vs_service_user)*get.num_services); ret = -EINVAL; goto out; @@ -1996,7 +2000,7 @@ struct ip_vs_service *svc; if (*len != sizeof(get)) { - IP_VS_ERR("length: %u != %u\n", *len, sizeof(get)); + IP_VS_ERR("length: %u != %Zu\n", *len, sizeof(get)); ret = -EINVAL; goto out; } @@ -2030,7 +2034,7 @@ struct ip_vs_get_dests get; if (*len < sizeof(get)) { - IP_VS_ERR("length: %u < %u\n", *len, sizeof(get)); + IP_VS_ERR("length: %u < %Zu\n", *len, sizeof(get)); ret = -EINVAL; goto out; } @@ -2040,7 +2044,7 @@ } if (*len != (sizeof(get) + sizeof(struct ip_vs_dest_user)*get.num_dests)) { - IP_VS_ERR("length: %u != %u\n", *len, + IP_VS_ERR("length: %u != %Zu\n", *len, sizeof(get)+sizeof(struct ip_vs_dest_user)*get.num_dests); ret = -EINVAL; goto out; @@ -2054,7 +2058,7 @@ struct ip_vs_timeout_user u; if (*len < sizeof(u)) { - IP_VS_ERR("length: %u < %u\n", *len, sizeof(u)); + IP_VS_ERR("length: %u < %Zu\n", *len, sizeof(u)); ret = -EINVAL; goto out; } @@ -2069,7 +2073,7 @@ struct ip_vs_daemon_user u; if (*len < sizeof(u)) { - IP_VS_ERR("length: %u < %u\n", *len, sizeof(u)); + IP_VS_ERR("length: %u < %Zu\n", *len, sizeof(u)); ret = -EINVAL; goto out; } diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_dh.c linux-2.4.26/net/ipv4/ipvs/ip_vs_dh.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_dh.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_dh.c 2004-04-14 06:05:41.000000000 -0700 @@ -37,12 +37,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_ftp.c linux-2.4.26/net/ipv4/ipvs/ip_vs_ftp.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_ftp.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_ftp.c 2004-04-14 06:05:41.000000000 -0700 @@ -24,15 +24,11 @@ * */ -#include #include -#include -#include #include #include #include #include -#include #include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_lblc.c linux-2.4.26/net/ipv4/ipvs/ip_vs_lblc.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_lblc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_lblc.c 2004-04-14 06:05:41.000000000 -0700 @@ -41,14 +41,10 @@ * me to write this module. */ -#include #include -#include -#include #include -#include -/* for systcl */ +/* for sysctl */ #include #include @@ -69,7 +65,7 @@ * entries that haven't been touched for a day. */ #define COUNT_FOR_FULL_EXPIRATION 30 -int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ; +static int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ; /* diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_lblcr.c linux-2.4.26/net/ipv4/ipvs/ip_vs_lblcr.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_lblcr.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_lblcr.c 2004-04-14 06:05:41.000000000 -0700 @@ -39,14 +39,10 @@ * */ -#include #include -#include -#include #include -#include -/* for systcl */ +/* for sysctl */ #include #include /* for proc_net_create/proc_net_remove */ @@ -69,7 +65,7 @@ * entries that haven't been touched for a day. */ #define COUNT_FOR_FULL_EXPIRATION 30 -int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ; +static int sysctl_ip_vs_lblcr_expiration = 24*60*60*HZ; /* diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_lc.c linux-2.4.26/net/ipv4/ipvs/ip_vs_lc.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_lc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_lc.c 2004-04-14 06:05:41.000000000 -0700 @@ -16,12 +16,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_nq.c linux-2.4.26/net/ipv4/ipvs/ip_vs_nq.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_nq.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_nq.c 2004-04-14 06:05:41.000000000 -0700 @@ -33,12 +33,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_rr.c linux-2.4.26/net/ipv4/ipvs/ip_vs_rr.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_rr.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_rr.c 2004-04-14 06:05:41.000000000 -0700 @@ -21,12 +21,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_sched.c linux-2.4.26/net/ipv4/ipvs/ip_vs_sched.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_sched.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_sched.c 2004-04-14 06:05:41.000000000 -0700 @@ -19,10 +19,7 @@ * */ -#include #include -#include -#include #include #include #include /* for local_bh_* */ diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_sed.c linux-2.4.26/net/ipv4/ipvs/ip_vs_sed.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_sed.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_sed.c 2004-04-14 06:05:41.000000000 -0700 @@ -37,12 +37,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_sh.c linux-2.4.26/net/ipv4/ipvs/ip_vs_sh.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_sh.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_sh.c 2004-04-14 06:05:41.000000000 -0700 @@ -34,12 +34,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_sync.c linux-2.4.26/net/ipv4/ipvs/ip_vs_sync.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_sync.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_sync.c 2004-04-14 06:05:41.000000000 -0700 @@ -13,17 +13,9 @@ * through multicast */ -#define __KERNEL_SYSCALLS__ /* for waitpid */ - -#include #include -#include -#include #include #include -#include -#include -#include #include #include @@ -559,8 +551,6 @@ } -static int errno; - static DECLARE_WAIT_QUEUE_HEAD(sync_wait); static pid_t sync_pid = 0; @@ -679,9 +669,9 @@ set_fs(KERNEL_DS); if (ip_vs_sync_state == IP_VS_STATE_MASTER) - sprintf(current->comm, "ipvs syncmaster"); + sprintf(current->comm, "ipvs_syncmaster"); else if (ip_vs_sync_state == IP_VS_STATE_BACKUP) - sprintf(current->comm, "ipvs syncbackup"); + sprintf(current->comm, "ipvs_syncbackup"); else IP_VS_BUG(); spin_lock_irq(¤t->sigmask_lock); @@ -726,10 +716,19 @@ static int fork_sync_thread(void *startup) { + pid_t pid; + /* fork the sync thread here, then the parent process of the sync thread is the init process after this thread exits. */ - if (kernel_thread(sync_thread, startup, 0) < 0) - IP_VS_BUG(); + repeat: + if ((pid = kernel_thread(sync_thread, startup, 0)) < 0) { + IP_VS_ERR("could not create sync_thread due to %d... " + "retrying.\n", pid); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + goto repeat; + } + return 0; } @@ -738,7 +737,6 @@ { DECLARE_COMPLETION(startup); pid_t pid; - int waitpid_result; if (sync_pid) return -EEXIST; @@ -750,12 +748,13 @@ ip_vs_sync_state = state; strcpy(ip_vs_mcast_ifn, mcast_ifn); - if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) - IP_VS_BUG(); - - if ((waitpid_result = waitpid(pid, NULL, __WCLONE)) != pid) { - IP_VS_ERR("%s: waitpid(%d,...) failed, errno %d\n", - __FUNCTION__, pid, -waitpid_result); + repeat: + if ((pid = kernel_thread(fork_sync_thread, &startup, 0)) < 0) { + IP_VS_ERR("could not create fork_sync_thread due to %d... " + "retrying.\n", pid); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + goto repeat; } wait_for_completion(&startup); diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_wlc.c linux-2.4.26/net/ipv4/ipvs/ip_vs_wlc.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_wlc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_wlc.c 2004-04-14 06:05:41.000000000 -0700 @@ -21,12 +21,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/ipvs/ip_vs_wrr.c linux-2.4.26/net/ipv4/ipvs/ip_vs_wrr.c --- linux-2.4.25/net/ipv4/ipvs/ip_vs_wrr.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/ipvs/ip_vs_wrr.c 2004-04-14 06:05:41.000000000 -0700 @@ -20,12 +20,8 @@ * */ -#include #include -#include -#include #include -#include #include diff -urN linux-2.4.25/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.26/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.4.25/net/ipv4/netfilter/ip_nat_standalone.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv4/netfilter/ip_nat_standalone.c 2004-04-14 06:05:41.000000000 -0700 @@ -114,7 +114,16 @@ WRITE_LOCK(&ip_nat_lock); /* Seen it before? This can happen for loopback, retrans, or local packets.. */ - if (!(info->initialized & (1 << maniptype))) { + if (!(info->initialized & (1 << maniptype)) +#ifndef CONFIG_IP_NF_NAT_LOCAL + /* If this session has already been confirmed we must not + * touch it again even if there is no mapping set up. + * Can only happen on local->local traffic with + * CONFIG_IP_NF_NAT_LOCAL disabled. + */ + && !(ct->status & IPS_CONFIRMED) +#endif + ) { unsigned int ret; if (ct->master diff -urN linux-2.4.25/net/ipv4/netfilter/ipt_ECN.c linux-2.4.26/net/ipv4/netfilter/ipt_ECN.c --- linux-2.4.25/net/ipv4/netfilter/ipt_ECN.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.26/net/ipv4/netfilter/ipt_ECN.c 2004-04-14 06:05:41.000000000 -0700 @@ -4,7 +4,7 @@ * * This software is distributed under GNU GPL v2, 1991 * - * ipt_ECN.c,v 1.4 2002/08/05 19:36:51 laforge Exp + * ipt_ECN.c,v 1.7 2003/12/15 15:18:06 laforge Exp */ #include @@ -59,8 +59,8 @@ const struct ipt_ECN_info *einfo) { - struct tcphdr *tcph = (void *) iph + iph->ihl * 4; - u_int16_t *tcpflags = (u_int16_t *)tcph + 6; + struct tcphdr *tcph; + u_int16_t *tcpflags; u_int16_t diffs[2]; /* raw socket (tcpdump) may have clone of incoming @@ -71,9 +71,12 @@ return NF_DROP; kfree_skb(*pskb); *pskb = nskb; - iph = (*pskb)->nh.iph; } + iph = (*pskb)->nh.iph; + tcph = (void *) iph + iph->ihl * 4; + tcpflags = (u_int16_t *)tcph + 6; + diffs[0] = *tcpflags; if (einfo->operation & IPT_ECN_OP_SET_ECE diff -urN linux-2.4.25/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.4.26/net/ipv4/netfilter/ipt_MASQUERADE.c --- linux-2.4.25/net/ipv4/netfilter/ipt_MASQUERADE.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv4/netfilter/ipt_MASQUERADE.c 2004-04-14 06:05:41.000000000 -0700 @@ -32,7 +32,7 @@ const struct ip_nat_multi_range *mr = targinfo; if (strcmp(tablename, "nat") != 0) { - DEBUGP("masquerade_check: bad table `%s'.\n", table); + DEBUGP("masquerade_check: bad table `%s'.\n", tablename); return 0; } if (targinfosize != IPT_ALIGN(sizeof(*mr))) { diff -urN linux-2.4.25/net/ipv4/sysctl_net_ipv4.c linux-2.4.26/net/ipv4/sysctl_net_ipv4.c --- linux-2.4.25/net/ipv4/sysctl_net_ipv4.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.26/net/ipv4/sysctl_net_ipv4.c 2004-04-14 06:05:41.000000000 -0700 @@ -38,6 +38,7 @@ /* From igmp.c */ extern int sysctl_igmp_max_memberships; +extern int sysctl_igmp_max_msf; /* From inetpeer.c */ extern int inet_peer_threshold; @@ -52,6 +53,9 @@ static int ip_local_port_range_max[] = { 65535, 65535 }; #endif +/* From tcp_input.c */ +extern int sysctl_tcp_westwood; + struct ipv4_config ipv4_config; extern ctl_table ipv4_route_table[]; @@ -68,7 +72,7 @@ ret = proc_dointvec(ctl, write, filp, buffer, lenp); if (write && ipv4_devconf.forwarding != val) - inet_forward_change(); + inet_forward_change(ipv4_devconf.forwarding); return ret; } @@ -84,7 +88,7 @@ if (get_user(new,(int *)newval)) return -EFAULT; if (new != ipv4_devconf.forwarding) - inet_forward_change(); + inet_forward_change(new); return 0; /* caller does change again and handles handles oldval */ } @@ -182,6 +186,8 @@ {NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships", &sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec}, #endif + {NET_IPV4_IGMP_MAX_MSF, "igmp_max_msf", + &sysctl_igmp_max_msf, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_INET_PEER_THRESHOLD, "inet_peer_threshold", &inet_peer_threshold, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_INET_PEER_MINTTL, "inet_peer_minttl", @@ -229,6 +235,9 @@ {NET_IPV4_IPFRAG_SECRET_INTERVAL, "ipfrag_secret_interval", &sysctl_ipfrag_secret_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, &sysctl_jiffies}, + {NET_TCP_WESTWOOD, "tcp_westwood", + &sysctl_tcp_westwood, sizeof(int), 0644, NULL, + &proc_dointvec}, {0} }; diff -urN linux-2.4.25/net/ipv4/tcp_input.c linux-2.4.26/net/ipv4/tcp_input.c --- linux-2.4.25/net/ipv4/tcp_input.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/tcp_input.c 2004-04-14 06:05:41.000000000 -0700 @@ -61,6 +61,7 @@ * Panu Kuhlberg: Experimental audit of TCP (re)transmission * engine. Lots of bugs are found. * Pasi Sarolahti: F-RTO for dealing with spurious RTOs + * Angelo Dell'Aera: TCP Westwood+ support */ #include @@ -89,6 +90,8 @@ int sysctl_tcp_max_orphans = NR_FILE; int sysctl_tcp_frto = 0; +int sysctl_tcp_westwood = 0; + #define FLAG_DATA 0x01 /* Incoming frame contained data. */ #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ #define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ @@ -470,6 +473,8 @@ tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN); tp->rtt_seq = tp->snd_nxt; } + + tcp_westwood_update_rtt(tp, tp->srtt >> 3); } /* Calculate rto without backoff. This is the second half of Van Jacobson's @@ -1068,7 +1073,9 @@ tp->snd_una == tp->high_seq || (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) { tp->prior_ssthresh = tcp_current_ssthresh(tp); - tp->snd_ssthresh = tcp_recalc_ssthresh(tp); + + if (!(tcp_westwood_ssthresh(tp))) + tp->snd_ssthresh = tcp_recalc_ssthresh(tp); } tp->snd_cwnd = 1; tp->snd_cwnd_cnt = 0; @@ -1380,11 +1387,24 @@ static void tcp_cwnd_down(struct tcp_opt *tp) { int decr = tp->snd_cwnd_cnt + 1; + __u32 limit; + + /* + * TCP Westwood + * Here limit is evaluated as BWestimation*RTTmin (for obtaining it + * in packets we use mss_cache). If sysctl_tcp_westwood is off + * tcp_westwood_bw_rttmin() returns 0. In such case snd_ssthresh is + * still used as usual. It prevents other strange cases in which + * BWE*RTTmin could assume value 0. It should not happen but... + */ + + if (!(limit = tcp_westwood_bw_rttmin(tp))) + limit = tp->snd_ssthresh/2; tp->snd_cwnd_cnt = decr&1; decr >>= 1; - if (decr && tp->snd_cwnd > tp->snd_ssthresh/2) + if (decr && tp->snd_cwnd > limit) tp->snd_cwnd -= decr; tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1); @@ -1528,7 +1548,8 @@ static __inline__ void tcp_complete_cwr(struct tcp_opt *tp) { - tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); + if (!(tcp_westwood_complete_cwr(tp))) + tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh); tp->snd_cwnd_stamp = tcp_time_stamp; } @@ -2016,6 +2037,234 @@ tp->frto_counter = (tp->frto_counter + 1) % 3; } +/* + * TCP Westwood+ + */ + +/* + * @westwood_do_filter + * Low-pass filter. Implemented using constant coeffients. + */ + +static inline __u32 westwood_do_filter(__u32 a, __u32 b) +{ + return (((7 * a) + b) >> 3); +} + +static void westwood_filter(struct sock *sk, __u32 delta) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + tp->westwood.bw_ns_est = + westwood_do_filter(tp->westwood.bw_ns_est, + tp->westwood.bk / delta); + tp->westwood.bw_est = + westwood_do_filter(tp->westwood.bw_est, + tp->westwood.bw_ns_est); +} + +/* @westwood_update_rttmin + * It is used to update RTTmin. In this case we MUST NOT use + * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN! + */ + +static inline __u32 westwood_update_rttmin(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + __u32 rttmin = tp->westwood.rtt_min; + + if (tp->westwood.rtt == 0) + return rttmin; + + if (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin) + rttmin = tp->westwood.rtt; + + return rttmin; +} + +/* + * @westwood_acked + * Evaluate increases for dk. + */ + +static __u32 westwood_acked(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + return ((tp->snd_una) - (tp->westwood.snd_una)); +} + +/* + * @westwood_new_window + * It evaluates if we are receiving data inside the same RTT window as + * when we started. + * Return value: + * It returns 0 if we are still evaluating samples in the same RTT + * window, 1 if the sample has to be considered in the next window. + */ + +static int westwood_new_window(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + __u32 left_bound; + __u32 rtt; + int ret = 0; + + left_bound = tp->westwood.rtt_win_sx; + rtt = max(tp->westwood.rtt, (__u32)TCP_WESTWOOD_RTT_MIN); + + /* + * A RTT-window has passed. Be careful since if RTT is less than + * 50ms we don't filter but we continue 'building the sample'. + * This minimum limit was choosen since an estimation on small + * time intervals is better to avoid... + * Obvioulsy on a LAN we reasonably will always have + * right_bound = left_bound + WESTWOOD_RTT_MIN + */ + + if ((left_bound + rtt) < tcp_time_stamp) + ret = 1; + + return ret; +} + +/* + * @westwood_update_window + * It updates RTT evaluation window if it is the right moment to do + * it. If so it calls filter for evaluating bandwidth. + */ + +static void __westwood_update_window(struct sock *sk, __u32 now) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + __u32 delta = now - tp->westwood.rtt_win_sx; + + if (!delta) + return; + + if (tp->westwood.rtt) + westwood_filter(sk, delta); + + tp->westwood.bk = 0; + tp->westwood.rtt_win_sx = tcp_time_stamp; +} + +static void westwood_update_window(struct sock *sk, __u32 now) +{ + if (westwood_new_window(sk)) + __westwood_update_window(sk, now); +} + +/* + * @__tcp_westwood_fast_bw + * It is called when we are in fast path. In particular it is called when + * header prediction is successfull. In such case infact update is + * straight forward and doesn't need any particular care. + */ + +void __tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + westwood_update_window(sk, tcp_time_stamp); + + tp->westwood.bk += westwood_acked(sk); + tp->westwood.snd_una = tp->snd_una; + tp->westwood.rtt_min = westwood_update_rttmin(sk); +} + +/* + * @westwood_mss + * This function was inserted just to have the possibility to evaluate + * which value of MSS is better. Infact we can use neither mss_cache or + * mss_cache. Just testing we will know it! + */ + +static inline __u32 westwood_mss(struct tcp_opt *tp) +{ + return ((__u32)(tp->mss_cache)); +} + +/* + * @tcp_westwood_dupack_update + * It updates accounted and cumul_ack when receiving a dupack. + */ + +static void westwood_dupack_update(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + tp->westwood.accounted += westwood_mss(tp); + tp->westwood.cumul_ack = westwood_mss(tp); +} + +static inline int westwood_may_change_cumul(struct tcp_opt *tp) +{ + return ((tp->westwood.cumul_ack) > westwood_mss(tp)); +} + +static inline void westwood_partial_update(struct tcp_opt *tp) +{ + tp->westwood.accounted -= tp->westwood.cumul_ack; + tp->westwood.cumul_ack = westwood_mss(tp); +} + +static inline void westwood_complete_update(struct tcp_opt *tp) +{ + tp->westwood.cumul_ack -= tp->westwood.accounted; + tp->westwood.accounted = 0; +} + +/* + * @westwood_acked_count + * This function evaluates cumul_ack for evaluating dk in case of + * delayed or partial acks. + */ + +static __u32 westwood_acked_count(struct sock *sk) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + tp->westwood.cumul_ack = westwood_acked(sk); + + /* If cumul_ack is 0 this is a dupack since it's not moving + * tp->snd_una. + */ + if (!(tp->westwood.cumul_ack)) + westwood_dupack_update(sk); + + if (westwood_may_change_cumul(tp)) { + /* Partial or delayed ack */ + if ((tp->westwood.accounted) >= (tp->westwood.cumul_ack)) + westwood_partial_update(tp); + else + westwood_complete_update(tp); + } + + tp->westwood.snd_una = tp->snd_una; + + return tp->westwood.cumul_ack; +} + +/* + * @__tcp_westwood_slow_bw + * It is called when something is going wrong..even if there could + * be no problems! Infact a simple delayed packet may trigger a + * dupack. But we need to be careful in such case. + */ + +void __tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb) +{ + struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); + + westwood_update_window(sk, tcp_time_stamp); + + tp->westwood.bk += westwood_acked_count(sk); + tp->westwood.rtt_min = westwood_update_rttmin(sk); +} + +/* TCP Westwood+ routines end here */ + /* This routine deals with incoming acks, but not outgoing ones. */ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag) { @@ -2042,6 +2291,7 @@ */ tcp_update_wl(tp, ack, ack_seq); tp->snd_una = ack; + tcp_westwood_fast_bw(sk, skb); flag |= FLAG_WIN_UPDATE; NET_INC_STATS_BH(TCPHPAcks); @@ -2058,6 +2308,8 @@ if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th)) flag |= FLAG_ECE; + + tcp_westwood_slow_bw(sk, skb); } /* We passed data and got it acked, remove any soft error @@ -3796,7 +4048,6 @@ return 1; } - /* * This function implements the receiving procedure of RFC 793 for * all states except ESTABLISHED and TIME_WAIT. @@ -3827,6 +4078,8 @@ if(tp->af_specific->conn_request(sk, skb) < 0) return 1; + tcp_init_westwood(sk); + /* Now we have several options: In theory there is * nothing else in the frame. KA9Q has an option to * send data with the syn, BSD accepts data with the @@ -3848,6 +4101,8 @@ goto discard; case TCP_SYN_SENT: + tcp_init_westwood(sk); + queued = tcp_rcv_synsent_state_process(sk, skb, th, len); if (queued >= 0) return queued; diff -urN linux-2.4.25/net/ipv4/tcp_ipv4.c linux-2.4.26/net/ipv4/tcp_ipv4.c --- linux-2.4.25/net/ipv4/tcp_ipv4.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/tcp_ipv4.c 2004-04-14 06:05:41.000000000 -0700 @@ -1804,7 +1804,8 @@ do_time_wait: if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); - goto discard_and_relse; + tcp_tw_put((struct tcp_tw_bucket *) sk); + goto discard_it; } switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk, skb, th, skb->len)) { diff -urN linux-2.4.25/net/ipv4/udp.c linux-2.4.26/net/ipv4/udp.c --- linux-2.4.25/net/ipv4/udp.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv4/udp.c 2004-04-14 06:05:41.000000000 -0700 @@ -657,6 +657,7 @@ if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); +try_again: skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -722,7 +723,9 @@ skb_free_datagram(sk, skb); - return -EAGAIN; + if (noblock) + return -EAGAIN; + goto try_again; } int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) diff -urN linux-2.4.25/net/ipv6/exthdrs.c linux-2.4.26/net/ipv6/exthdrs.c --- linux-2.4.25/net/ipv6/exthdrs.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/ipv6/exthdrs.c 2004-04-14 06:05:41.000000000 -0700 @@ -783,7 +783,7 @@ * --ANK (980726) */ -int ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len) +int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len) { u8 nexthdr = *nexthdrp; @@ -798,8 +798,16 @@ if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) BUG(); if (nexthdr == NEXTHDR_FRAGMENT) { - struct frag_hdr *fhdr = (struct frag_hdr *) &hdr; - if (ntohs(fhdr->frag_off) & ~0x7) + unsigned short frag_off; + if (skb_copy_bits(skb, + start+offsetof(struct frag_hdr, + frag_off), + &frag_off, + sizeof(frag_off))) { + return -1; + } + + if (ntohs(frag_off) & ~0x7) break; hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) diff -urN linux-2.4.25/net/ipv6/icmp.c linux-2.4.26/net/ipv6/icmp.c --- linux-2.4.25/net/ipv6/icmp.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv6/icmp.c 2004-04-14 06:05:41.000000000 -0700 @@ -648,7 +648,13 @@ sk = icmpv6_socket_cpu(i)->sk; sk->allocation = GFP_ATOMIC; - sk->sndbuf = SK_WMEM_MAX*2; + + /* Enough space for 2 64K ICMP packets, including + * sk_buff struct overhead. + */ + sk->sndbuf = + (2 * ((64 * 1024) + sizeof(struct sk_buff))); + sk->prot->unhash(sk); } diff -urN linux-2.4.25/net/ipv6/ipv6_sockglue.c linux-2.4.26/net/ipv6/ipv6_sockglue.c --- linux-2.4.25/net/ipv6/ipv6_sockglue.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/ipv6/ipv6_sockglue.c 2004-04-14 06:05:41.000000000 -0700 @@ -452,10 +452,16 @@ } case MCAST_MSFILTER: { + extern int sysctl_optmem_max; + extern int sysctl_mld_max_msf; struct group_filter *gsf; if (optlen < GROUP_FILTER_SIZE(0)) goto e_inval; + if (optlen > sysctl_optmem_max) { + retv = -ENOBUFS; + break; + } gsf = (struct group_filter *)kmalloc(optlen,GFP_KERNEL); if (gsf == 0) { retv = -ENOBUFS; @@ -466,6 +472,18 @@ kfree(gsf); break; } + /* numsrc >= (4G-140)/128 overflow in 32 bits */ + if (gsf->gf_numsrc >= 0x1ffffffU || + gsf->gf_numsrc > sysctl_mld_max_msf) { + kfree(gsf); + retv = -ENOBUFS; + break; + } + if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { + kfree(gsf); + retv = -EINVAL; + break; + } retv = ip6_mc_msfilter(sk, gsf); kfree(gsf); diff -urN linux-2.4.25/net/ipv6/ipv6_syms.c linux-2.4.26/net/ipv6/ipv6_syms.c --- linux-2.4.25/net/ipv6/ipv6_syms.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv6/ipv6_syms.c 2004-04-14 06:05:41.000000000 -0700 @@ -33,3 +33,5 @@ EXPORT_SYMBOL(ipv6_get_saddr); EXPORT_SYMBOL(ipv6_chk_addr); EXPORT_SYMBOL(in6_dev_finish_destroy); +EXPORT_SYMBOL(ipv6_skip_exthdr); + diff -urN linux-2.4.25/net/ipv6/mcast.c linux-2.4.26/net/ipv6/mcast.c --- linux-2.4.25/net/ipv6/mcast.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv6/mcast.c 2004-04-14 06:05:41.000000000 -0700 @@ -163,6 +163,10 @@ #define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value) #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) +#define IPV6_MLD_MAX_MSF 10 + +int sysctl_mld_max_msf = IPV6_MLD_MAX_MSF; + /* * socket join on multicast group */ @@ -401,6 +405,10 @@ } /* else, add a new source to the filter */ + if (psl && psl->sl_count >= sysctl_mld_max_msf) { + err = -ENOBUFS; + goto done; + } if (!psl || psl->sl_count == psl->sl_max) { struct ip6_sf_socklist *newpsl; int count = IP6_SFBLOCK; diff -urN linux-2.4.25/net/ipv6/ndisc.c linux-2.4.26/net/ipv6/ndisc.c --- linux-2.4.25/net/ipv6/ndisc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv6/ndisc.c 2004-04-14 06:05:41.000000000 -0700 @@ -1002,7 +1002,7 @@ */ if (in6_dev->nd_parms) { - __u32 rtime = ntohl(ra_msg->retrans_timer); + unsigned long rtime = ntohl(ra_msg->retrans_timer); if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) { rtime = (rtime*HZ)/1000; diff -urN linux-2.4.25/net/ipv6/netfilter/ip6_tables.c linux-2.4.26/net/ipv6/netfilter/ip6_tables.c --- linux-2.4.25/net/ipv6/netfilter/ip6_tables.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv6/netfilter/ip6_tables.c 2004-04-14 06:05:41.000000000 -0700 @@ -1568,8 +1568,10 @@ u_int16_t datalen, int *hotdrop) { - const struct tcphdr *tcp = hdr; + const struct tcphdr *tcp; const struct ip6t_tcp *tcpinfo = matchinfo; + int tcpoff; + u8 nexthdr = skb->nh.ipv6h->nexthdr; /* To quote Alan: @@ -1590,6 +1592,24 @@ return 0; } + tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data; + tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff); + if (tcpoff < 0 || tcpoff > skb->len) { + duprintf("tcp_match: cannot skip exthdr. Dropping.\n"); + *hotdrop = 1; + return 0; + } else if (nexthdr == IPPROTO_FRAGMENT) + return 0; + else if (nexthdr != IPPROTO_TCP || + skb->len - tcpoff < sizeof(struct tcphdr)) { + /* cannot be occured */ + duprintf("tcp_match: cannot get TCP header. Dropping.\n"); + *hotdrop = 1; + return 0; + } + + tcp = (struct tcphdr *)(skb->data + tcpoff); + /* FIXME: Try tcp doff >> packet len against various stacks --RR */ #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg)) @@ -1640,8 +1660,10 @@ u_int16_t datalen, int *hotdrop) { - const struct udphdr *udp = hdr; + const struct udphdr *udp; const struct ip6t_udp *udpinfo = matchinfo; + int udpoff; + u8 nexthdr = skb->nh.ipv6h->nexthdr; if (offset == 0 && datalen < sizeof(struct udphdr)) { /* We've been asked to examine this packet, and we @@ -1651,6 +1673,23 @@ return 0; } + udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data; + udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff); + if (udpoff < 0 || udpoff > skb->len) { + duprintf("udp_match: cannot skip exthdr. Dropping.\n"); + *hotdrop = 1; + return 0; + } else if (nexthdr == IPPROTO_FRAGMENT) + return 0; + else if (nexthdr != IPPROTO_UDP || + skb->len - udpoff < sizeof(struct udphdr)) { + duprintf("udp_match: cannot get UDP header. Dropping.\n"); + *hotdrop = 1; + return 0; + } + + udp = (struct udphdr *)(skb->data + udpoff); + /* Must not be a fragment. */ return !offset && port_match(udpinfo->spts[0], udpinfo->spts[1], diff -urN linux-2.4.25/net/ipv6/sysctl_net_ipv6.c linux-2.4.26/net/ipv6/sysctl_net_ipv6.c --- linux-2.4.25/net/ipv6/sysctl_net_ipv6.c 2003-06-13 07:51:39.000000000 -0700 +++ linux-2.4.26/net/ipv6/sysctl_net_ipv6.c 2004-04-14 06:05:41.000000000 -0700 @@ -24,6 +24,8 @@ {NET_IPV6_ICMP, "icmp", NULL, 0, 0500, ipv6_icmp_table}, {NET_IPV6_BINDV6ONLY, "bindv6only", &sysctl_ipv6_bindv6only, sizeof(int), 0644, NULL, &proc_dointvec}, + {NET_IPV6_MLD_MAX_MSF, "mld_max_msf", + &sysctl_mld_max_msf, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; diff -urN linux-2.4.25/net/ipv6/tcp_ipv6.c linux-2.4.26/net/ipv6/tcp_ipv6.c --- linux-2.4.25/net/ipv6/tcp_ipv6.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/ipv6/tcp_ipv6.c 2004-04-14 06:05:41.000000000 -0700 @@ -1647,7 +1647,7 @@ do_time_wait: if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { TCP_INC_STATS_BH(TcpInErrs); - sock_put(sk); + tcp_tw_put((struct tcp_tw_bucket *) sk); goto discard_it; } diff -urN linux-2.4.25/net/ipv6/udp.c linux-2.4.26/net/ipv6/udp.c --- linux-2.4.25/net/ipv6/udp.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/ipv6/udp.c 2004-04-14 06:05:41.000000000 -0700 @@ -400,6 +400,7 @@ if (flags & MSG_ERRQUEUE) return ipv6_recv_error(sk, msg, len); +try_again: skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; @@ -476,12 +477,13 @@ kfree_skb(skb); } - /* Error for blocking case is chosen to masquerade - as some normal condition. - */ - err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; - UDP6_INC_STATS_USER(UdpInErrors); - goto out_free; + skb_free_datagram(sk, skb); + + if (flags & MSG_DONTWAIT) { + UDP6_INC_STATS_USER(UdpInErrors); + return -EAGAIN; + } + goto try_again; } void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, diff -urN linux-2.4.25/net/netsyms.c linux-2.4.26/net/netsyms.c --- linux-2.4.25/net/netsyms.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/netsyms.c 2004-04-14 06:05:41.000000000 -0700 @@ -40,6 +40,7 @@ #ifdef CONFIG_NET extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; +extern int sysctl_optmem_max; #endif #ifdef CONFIG_INET @@ -261,6 +262,8 @@ EXPORT_SYMBOL(icmp_err_convert); EXPORT_SYMBOL(ip_options_compile); EXPORT_SYMBOL(ip_options_undo); +EXPORT_SYMBOL(arp_create); +EXPORT_SYMBOL(arp_xmit); EXPORT_SYMBOL(arp_send); EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(__ip_select_ident); @@ -548,6 +551,7 @@ #ifdef CONFIG_SYSCTL EXPORT_SYMBOL(sysctl_wmem_max); EXPORT_SYMBOL(sysctl_rmem_max); +EXPORT_SYMBOL(sysctl_optmem_max); #ifdef CONFIG_INET EXPORT_SYMBOL(sysctl_ip_default_ttl); #endif diff -urN linux-2.4.25/net/packet/af_packet.c linux-2.4.26/net/packet/af_packet.c --- linux-2.4.25/net/packet/af_packet.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.26/net/packet/af_packet.c 2004-04-14 06:05:41.000000000 -0700 @@ -34,6 +34,8 @@ * Alexey Kuznetsov : Untied from IPv4 stack. * Cyrus Durgin : Fixed kerneld for kmod. * Michal Ostrowski : Module initialization cleanup. + * Ulises Alonso : Frame number limit removal and + * packet_set_ring memory leak. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -176,29 +178,46 @@ struct packet_opt { + struct tpacket_stats stats; +#ifdef CONFIG_PACKET_MMAP + unsigned long *pg_vec; + unsigned int head; + unsigned int frames_per_block; + unsigned int frame_size; + unsigned int frame_max; + int copy_thresh; +#endif struct packet_type prot_hook; spinlock_t bind_lock; char running; /* prot_hook is attached*/ int ifindex; /* bound device */ - struct tpacket_stats stats; #ifdef CONFIG_PACKET_MULTICAST struct packet_mclist *mclist; #endif #ifdef CONFIG_PACKET_MMAP atomic_t mapped; - unsigned long *pg_vec; unsigned int pg_vec_order; unsigned int pg_vec_pages; unsigned int pg_vec_len; - - struct tpacket_hdr **iovec; - unsigned int frame_size; - unsigned int iovmax; - unsigned int head; - int copy_thresh; #endif }; +#ifdef CONFIG_PACKET_MMAP + +static inline unsigned long packet_lookup_frame(struct packet_opt *po, unsigned int position) +{ + unsigned int pg_vec_pos, frame_offset; + unsigned long frame; + + pg_vec_pos = position / po->frames_per_block; + frame_offset = position % po->frames_per_block; + + frame = (unsigned long) (po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); + + return frame; +} +#endif + void packet_sock_destruct(struct sock *sk) { BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); @@ -590,11 +609,11 @@ snaplen = skb->len-skb->data_len; spin_lock(&sk->receive_queue.lock); - h = po->iovec[po->head]; + h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head); if (h->tp_status) goto ring_is_full; - po->head = po->head != po->iovmax ? po->head+1 : 0; + po->head = po->head != po->frame_max ? po->head+1 : 0; po->stats.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; @@ -1555,10 +1574,13 @@ unsigned int mask = datagram_poll(file, sock, wait); spin_lock_bh(&sk->receive_queue.lock); - if (po->iovec) { - unsigned last = po->head ? po->head-1 : po->iovmax; + if (po->pg_vec) { + unsigned last = po->head ? po->head-1 : po->frame_max; + struct tpacket_hdr *h; + + h = (struct tpacket_hdr *)packet_lookup_frame(po, last); - if (po->iovec[last]->tp_status) + if (h->tp_status) mask |= POLLIN | POLLRDNORM; } spin_unlock_bh(&sk->receive_queue.lock); @@ -1618,16 +1640,18 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) { unsigned long *pg_vec = NULL; - struct tpacket_hdr **io_vec = NULL; struct packet_opt *po = sk->protinfo.af_packet; int order = 0; int err = 0; if (req->tp_block_nr) { int i, l; - int frames_per_block; /* Sanity tests and some calculations */ + + if (po->pg_vec) + return -EBUSY; + if ((int)req->tp_block_size <= 0) return -EINVAL; if (req->tp_block_size&(PAGE_SIZE-1)) @@ -1636,10 +1660,11 @@ return -EINVAL; if (req->tp_frame_size&(TPACKET_ALIGNMENT-1)) return -EINVAL; - frames_per_block = req->tp_block_size/req->tp_frame_size; - if (frames_per_block <= 0) + + po->frames_per_block = req->tp_block_size/req->tp_frame_size; + if (po->frames_per_block <= 0) return -EINVAL; - if (frames_per_block*req->tp_block_nr != req->tp_frame_nr) + if (po->frames_per_block*req->tp_block_nr != req->tp_frame_nr) return -EINVAL; /* OK! */ @@ -1666,20 +1691,16 @@ } /* Page vector is allocated */ - /* Draw frames */ - io_vec = kmalloc(req->tp_frame_nr*sizeof(struct tpacket_hdr*), GFP_KERNEL); - if (io_vec == NULL) - goto out_free_pgvec; - memset(io_vec, 0, req->tp_frame_nr*sizeof(struct tpacket_hdr*)); - l = 0; for (i=0; itp_block_nr; i++) { unsigned long ptr = pg_vec[i]; + struct tpacket_hdr *header; int k; - for (k=0; ktp_status = TP_STATUS_KERNEL; + for (k=0; kframes_per_block; k++) { + + header = (struct tpacket_hdr*)ptr; + header->tp_status = TP_STATUS_KERNEL; ptr += req->tp_frame_size; } } @@ -1704,8 +1725,7 @@ spin_lock_bh(&sk->receive_queue.lock); pg_vec = XC(po->pg_vec, pg_vec); - io_vec = XC(po->iovec, io_vec); - po->iovmax = req->tp_frame_nr-1; + po->frame_max = req->tp_frame_nr-1; po->head = 0; po->frame_size = req->tp_frame_size; spin_unlock_bh(&sk->receive_queue.lock); @@ -1714,7 +1734,7 @@ req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr); po->pg_vec_pages = req->tp_block_size/PAGE_SIZE; - po->prot_hook.func = po->iovec ? tpacket_rcv : packet_rcv; + po->prot_hook.func = po->pg_vec ? tpacket_rcv : packet_rcv; skb_queue_purge(&sk->receive_queue); #undef XC if (atomic_read(&po->mapped)) @@ -1728,9 +1748,6 @@ release_sock(sk); - if (io_vec) - kfree(io_vec); - out_free_pgvec: if (pg_vec) free_pg_vec(pg_vec, order, req->tp_block_nr); diff -urN linux-2.4.25/net/sched/Config.in linux-2.4.26/net/sched/Config.in --- linux-2.4.25/net/sched/Config.in 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/Config.in 2004-04-14 06:05:41.000000000 -0700 @@ -15,6 +15,7 @@ tristate ' TEQL queue' CONFIG_NET_SCH_TEQL tristate ' TBF queue' CONFIG_NET_SCH_TBF tristate ' GRED queue' CONFIG_NET_SCH_GRED +tristate ' Network delay simulator' CONFIG_NET_SCH_DELAY tristate ' Diffserv field marker' CONFIG_NET_SCH_DSMARK if [ "$CONFIG_NETFILTER" = "y" ]; then tristate ' Ingress Qdisc' CONFIG_NET_SCH_INGRESS diff -urN linux-2.4.25/net/sched/Makefile linux-2.4.26/net/sched/Makefile --- linux-2.4.25/net/sched/Makefile 2002-11-28 15:53:16.000000000 -0800 +++ linux-2.4.26/net/sched/Makefile 2004-04-14 06:05:41.000000000 -0700 @@ -14,6 +14,7 @@ obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o obj-$(CONFIG_NET_SCH_CSZ) += sch_csz.o +obj-$(CONFIG_NET_SCH_DELAY) += sch_delay.o obj-$(CONFIG_NET_SCH_HPFQ) += sch_hpfq.o obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o diff -urN linux-2.4.25/net/sched/sch_delay.c linux-2.4.26/net/sched/sch_delay.c --- linux-2.4.25/net/sched/sch_delay.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/net/sched/sch_delay.c 2004-04-14 06:05:41.000000000 -0700 @@ -0,0 +1,277 @@ +/* + * net/sched/sch_delay.c Simple constant delay + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Stephen Hemminger + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Network delay simulator + This scheduler adds a fixed delay to all packets. + Similar to NISTnet and BSD Dummynet. + + It uses byte fifo underneath similar to TBF */ +struct dly_sched_data { + u32 latency; + u32 limit; + struct timer_list timer; + struct Qdisc *qdisc; +}; + +/* Time stamp put into socket buffer control block */ +struct dly_skb_cb { + psched_time_t queuetime; +}; + +/* Enqueue packets with underlying discipline (fifo) + * but mark them with current time first. + */ +static int dly_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb; + int ret; + + PSCHED_GET_TIME(cb->queuetime); + + /* Queue to underlying scheduler */ + ret = q->qdisc->enqueue(skb, q->qdisc); + if (ret) + sch->stats.drops++; + else { + sch->q.qlen++; + sch->stats.bytes += skb->len; + sch->stats.packets++; + } + return 0; +} + +/* Requeue packets but don't change time stamp */ +static int dly_requeue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + int ret; + + ret = q->qdisc->ops->requeue(skb, q->qdisc); + if (ret == 0) + sch->q.qlen++; + return ret; +} + +static unsigned int dly_drop(struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + unsigned int len; + + len = q->qdisc->ops->drop(q->qdisc); + if (len) { + sch->q.qlen--; + sch->stats.drops++; + } + return len; +} + +/* Dequeue packet. + * If packet needs to be held up, then stop the + * queue and set timer to wakeup later. + */ +static struct sk_buff *dly_dequeue(struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + struct sk_buff *skb = q->qdisc->dequeue(q->qdisc); + + if (skb) { + struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb; + psched_time_t now; + long diff; + + PSCHED_GET_TIME(now); + diff = q->latency - PSCHED_TDIFF(now, cb->queuetime); + + if (diff <= 0) { + sch->q.qlen--; + sch->flags &= ~TCQ_F_THROTTLED; + return skb; + } + + if (!netif_queue_stopped(sch->dev)) { + long delay = PSCHED_US2JIFFIE(diff); + if (delay <= 0) + delay = 1; + mod_timer(&q->timer, jiffies+delay); + } + + if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { + sch->q.qlen--; + sch->stats.drops++; + } + sch->flags |= TCQ_F_THROTTLED; + } + return NULL; +} + +static void dly_reset(struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + + qdisc_reset(q->qdisc); + sch->q.qlen = 0; + sch->flags &= ~TCQ_F_THROTTLED; + del_timer(&q->timer); +} + +static void dly_timer(unsigned long arg) +{ + struct Qdisc *sch = (struct Qdisc *)arg; + + sch->flags &= ~TCQ_F_THROTTLED; + netif_schedule(sch->dev); +} + +/* Tell Fifo the new limit. */ +static int change_limit(struct Qdisc *q, u32 limit) +{ + struct rtattr *rta; + int ret; + + rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); + if (!rta) + return -ENOMEM; + + rta->rta_type = RTM_NEWQDISC; + ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; + ret = q->ops->change(q, rta); + kfree(rta); + + return ret; +} + +/* Setup underlying FIFO discipline */ +static int dly_change(struct Qdisc *sch, struct rtattr *opt) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + struct tc_dly_qopt *qopt = RTA_DATA(opt); + int err; + + if (q->qdisc == &noop_qdisc) { + struct Qdisc *child + = qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops); + if (!child) + return -EINVAL; + q->qdisc = child; + } + + err = change_limit(q->qdisc, qopt->limit); + if (err) { + qdisc_destroy(q->qdisc); + q->qdisc = &noop_qdisc; + } else { + q->latency = qopt->latency; + q->limit = qopt->limit; + } + return err; +} + +static int dly_init(struct Qdisc *sch, struct rtattr *opt) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + int err; + + if (!opt) + return -EINVAL; + + MOD_INC_USE_COUNT; + + init_timer(&q->timer); + q->timer.function = dly_timer; + q->timer.data = (unsigned long) sch; + q->qdisc = &noop_qdisc; + + err = dly_change(sch, opt); + if (err) + MOD_DEC_USE_COUNT; + + return err; +} + +static void dly_destroy(struct Qdisc *sch) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + + del_timer(&q->timer); + qdisc_destroy(q->qdisc); + q->qdisc = &noop_qdisc; + + MOD_DEC_USE_COUNT; +} + +static int dly_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct dly_sched_data *q = (struct dly_sched_data *)sch->data; + unsigned char *b = skb->tail; + struct tc_dly_qopt qopt; + + qopt.latency = q->latency; + qopt.limit = q->limit; + + RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); + + return skb->len; + +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +struct Qdisc_ops dly_qdisc_ops = { + .id = "delay", + .priv_size = sizeof(struct dly_sched_data), + .enqueue = dly_enqueue, + .dequeue = dly_dequeue, + .requeue = dly_requeue, + .drop = dly_drop, + .init = dly_init, + .reset = dly_reset, + .destroy = dly_destroy, + .change = dly_change, + .dump = dly_dump, +}; + +#ifdef MODULE +int init_module(void) +{ + return register_qdisc(&dly_qdisc_ops); +} + +void cleanup_module(void) +{ + unregister_qdisc(&dly_qdisc_ops); +} +#endif +MODULE_LICENSE("GPL"); diff -urN linux-2.4.25/net/sched/sch_fifo.c linux-2.4.26/net/sched/sch_fifo.c --- linux-2.4.25/net/sched/sch_fifo.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_fifo.c 2004-04-14 06:05:41.000000000 -0700 @@ -140,10 +140,12 @@ struct fifo_sched_data *q = (void*)sch->data; if (opt == NULL) { + unsigned int limit = sch->dev->tx_queue_len ? : 1; + if (sch->ops == &bfifo_qdisc_ops) - q->limit = sch->dev->tx_queue_len*sch->dev->mtu; + q->limit = limit*sch->dev->mtu; else - q->limit = sch->dev->tx_queue_len; + q->limit = limit; } else { struct tc_fifo_qopt *ctl = RTA_DATA(opt); if (opt->rta_len < RTA_LENGTH(sizeof(*ctl))) diff -urN linux-2.4.25/net/sched/sch_gred.c linux-2.4.26/net/sched/sch_gred.c --- linux-2.4.25/net/sched/sch_gred.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_gred.c 2004-04-14 06:05:41.000000000 -0700 @@ -110,7 +110,7 @@ unsigned long qave=0; int i=0; - if (!t->initd && skb_queue_len(&sch->q) < sch->dev->tx_queue_len) { + if (!t->initd && skb_queue_len(&sch->q) < (sch->dev->tx_queue_len ? : 1)) { D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n"); goto do_enqueue; } diff -urN linux-2.4.25/net/sched/sch_hfsc.c linux-2.4.26/net/sched/sch_hfsc.c --- linux-2.4.25/net/sched/sch_hfsc.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_hfsc.c 2004-04-14 06:05:41.000000000 -0700 @@ -117,7 +117,7 @@ struct hfsc_class { - u32 classid; /* class id */ + u32 classid; /* class id */ unsigned int refcnt; /* usage count */ struct tc_stats stats; /* generic statistics */ @@ -137,28 +137,28 @@ struct list_head hlist; /* hash list member */ struct list_head dlist; /* drop list member */ - u64 cl_total; /* total work in bytes */ - u64 cl_cumul; /* cumulative work in bytes done by + u64 cl_total; /* total work in bytes */ + u64 cl_cumul; /* cumulative work in bytes done by real-time criteria */ - u64 cl_d; /* deadline*/ - u64 cl_e; /* eligible time */ - u64 cl_vt; /* virtual time */ - u64 cl_f; /* time when this class will fit for + u64 cl_d; /* deadline*/ + u64 cl_e; /* eligible time */ + u64 cl_vt; /* virtual time */ + u64 cl_f; /* time when this class will fit for link-sharing, max(myf, cfmin) */ - u64 cl_myf; /* my fit-time (calculated from this + u64 cl_myf; /* my fit-time (calculated from this class's own upperlimit curve) */ - u64 cl_myfadj; /* my fit-time adjustment (to cancel + u64 cl_myfadj; /* my fit-time adjustment (to cancel history dependence) */ - u64 cl_cfmin; /* earliest children's fit-time (used + u64 cl_cfmin; /* earliest children's fit-time (used with cl_myf to obtain cl_f) */ - u64 cl_cvtmin; /* minimal virtual time among the + u64 cl_cvtmin; /* minimal virtual time among the children fit for link-sharing (monotonic within a period) */ - u64 cl_vtadj; /* intra-period cumulative vt + u64 cl_vtadj; /* intra-period cumulative vt adjustment */ - u64 cl_vtoff; /* inter-period cumulative vt offset */ - u64 cl_cvtmax; /* max child's vt in the last period */ + u64 cl_vtoff; /* inter-period cumulative vt offset */ + u64 cl_cvtmax; /* max child's vt in the last period */ struct internal_sc cl_rsc; /* internal real-time service curve */ struct internal_sc cl_fsc; /* internal fair service curve */ @@ -178,15 +178,13 @@ struct hfsc_sched { - u16 defcls; /* default class id */ - + u16 defcls; /* default class id */ struct hfsc_class root; /* root class */ - struct hfsc_class *last_xmit; /* class that transmitted last - packet (for requeueing) */ struct list_head clhash[HFSC_HSIZE]; /* class hash */ struct list_head eligible; /* eligible list */ struct list_head droplist; /* active leaf class list (for dropping) */ + struct sk_buff_head requeue; /* requeued packet */ struct timer_list wd_timer; /* watchdog timer */ }; @@ -565,8 +563,7 @@ * service curve starting at (x, y). */ static void -rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, - u64 y) +rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) { rtsc->x = x; rtsc->y = y; @@ -625,8 +622,7 @@ * runtime service curve and the service curve starting at (x, y). */ static void -rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, - u64 y) +rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y) { u64 y1, y2, dx, dy; u32 dsm; @@ -1230,9 +1226,6 @@ list_del(&cl->siblings); hfsc_adjust_levels(cl->cl_parent); hfsc_purge_queue(sch, cl); - if (q->last_xmit == cl) - q->last_xmit = NULL; - if (--cl->refcnt == 0) hfsc_destroy_class(sch, cl); @@ -1540,6 +1533,7 @@ INIT_LIST_HEAD(&q->clhash[i]); INIT_LIST_HEAD(&q->eligible); INIT_LIST_HEAD(&q->droplist); + skb_queue_head_init(&q->requeue); q->root.refcnt = 1; q->root.classid = sch->handle; @@ -1619,10 +1613,9 @@ list_for_each_entry(cl, &q->clhash[i], hlist) hfsc_reset_class(cl); } - + __skb_queue_purge(&q->requeue); INIT_LIST_HEAD(&q->eligible); INIT_LIST_HEAD(&q->droplist); - q->last_xmit = NULL; del_timer(&q->wd_timer); sch->flags &= ~TCQ_F_THROTTLED; sch->q.qlen = 0; @@ -1639,7 +1632,7 @@ list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) hfsc_destroy_class(sch, cl); } - + __skb_queue_purge(&q->requeue); del_timer(&q->wd_timer); MOD_DEC_USE_COUNT; } @@ -1709,6 +1702,8 @@ if (sch->q.qlen == 0) return NULL; + if ((skb = __skb_dequeue(&q->requeue))) + goto out; PSCHED_GET_TIME(cur_time); @@ -1758,7 +1753,7 @@ set_passive(cl); } - q->last_xmit = cl; + out: sch->flags &= ~TCQ_F_THROTTLED; sch->q.qlen--; @@ -1769,28 +1764,10 @@ hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch) { struct hfsc_sched *q = (struct hfsc_sched *)sch->data; - struct hfsc_class *cl = q->last_xmit; - unsigned int len = skb->len; - int ret; - - if (cl == NULL) { - kfree_skb(skb); - sch->stats.drops++; - return NET_XMIT_DROP; - } - ret = cl->qdisc->ops->requeue(skb, cl->qdisc); - if (ret == NET_XMIT_SUCCESS) { - if (cl->qdisc->q.qlen == 1) - set_active(cl, len); - sch->q.qlen++; - } else { - cl->stats.drops++; - sch->stats.drops++; - } - q->last_xmit = NULL; - - return ret; + __skb_queue_head(&q->requeue, skb); + sch->q.qlen++; + return NET_XMIT_SUCCESS; } static unsigned int diff -urN linux-2.4.25/net/sched/sch_htb.c linux-2.4.26/net/sched/sch_htb.c --- linux-2.4.25/net/sched/sch_htb.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_htb.c 2004-04-14 06:05:41.000000000 -0700 @@ -21,9 +21,11 @@ * created test case so that I was able to fix nasty bug * Wilfried Weissmann * spotted bug in dequeue code and helped with fix + * Jiri Fojtasek + * fixed requeue routine * and many others. thanks. * - * $Id: sch_htb.c,v 1.24 2003/07/28 15:25:23 devik Exp devik $ + * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $ */ #include #include @@ -75,7 +77,7 @@ #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x3000d /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x30010 /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" @@ -304,7 +306,7 @@ rules in it */ if (skb->priority == sch->handle) return HTB_DIRECT; /* X:0 (direct flow) selected */ - if ((cl = htb_find(skb->priority,sch)) != NULL) + if ((cl = htb_find(skb->priority,sch)) != NULL && cl->level == 0) return cl; tcf = q->filter_list; @@ -433,13 +435,13 @@ cl->pq_key++; /* update the nearest event cache */ - if (q->near_ev_cache[cl->level] - cl->pq_key < 0x80000000) + if (time_after(q->near_ev_cache[cl->level], cl->pq_key)) q->near_ev_cache[cl->level] = cl->pq_key; while (*p) { struct htb_class *c; parent = *p; c = rb_entry(parent, struct htb_class, pq_node); - if (cl->pq_key - c->pq_key < 0x80000000) + if (time_after_eq(cl->pq_key, c->pq_key)) p = &parent->rb_right; else p = &parent->rb_left; @@ -717,7 +719,7 @@ sch->q.qlen++; sch->stats.packets++; sch->stats.bytes += skb->len; - HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); + HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); return NET_XMIT_SUCCESS; } @@ -726,16 +728,18 @@ { struct htb_sched *q = (struct htb_sched *)sch->data; struct htb_class *cl = htb_classify(skb,sch); + struct sk_buff *tskb; if (cl == HTB_DIRECT || !cl) { /* enqueue to helper queue */ if (q->direct_queue.qlen < q->direct_qlen && cl) { - __skb_queue_tail(&q->direct_queue, skb); - q->direct_pkts++; + __skb_queue_head(&q->direct_queue, skb); } else { - kfree_skb (skb); - sch->stats.drops++; - return NET_XMIT_DROP; + __skb_queue_head(&q->direct_queue, skb); + tskb = __skb_dequeue_tail(&q->direct_queue); + kfree_skb (tskb); + sch->stats.drops++; + return NET_XMIT_CN; } } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) { sch->stats.drops++; @@ -745,7 +749,7 @@ htb_activate (q,cl); sch->q.qlen++; - HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",cl?cl->classid:0,skb); + HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb); return NET_XMIT_SUCCESS; } @@ -878,7 +882,7 @@ while (p->rb_left) p = p->rb_left; cl = rb_entry(p, struct htb_class, pq_node); - if (cl->pq_key - (q->jiffies+1) < 0x80000000) { + if (time_after(cl->pq_key, q->jiffies)) { HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); return cl->pq_key - q->jiffies; } @@ -1057,7 +1061,7 @@ /* common case optimization - skip event handler quickly */ int m; long delay; - if (q->jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { + if (time_after_eq(q->jiffies, q->near_ev_cache[level])) { delay = htb_do_events(q,level); q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); #ifdef HTB_DEBUG @@ -1396,11 +1400,16 @@ #ifdef HTB_RATECM del_timer_sync (&q->rttim); #endif + /* This line used to be after htb_destroy_class call below + and surprisingly it worked in 2.4. But it must precede it + because filter need its target class alive to be able to call + unbind_filter on it (without Oops). */ + htb_destroy_filters(&q->filter_list); + while (!list_empty(&q->root)) htb_destroy_class (sch,list_entry(q->root.next, struct htb_class,sibling)); - htb_destroy_filters(&q->filter_list); __skb_queue_purge(&q->direct_queue); MOD_DEC_USE_COUNT; } @@ -1493,7 +1502,7 @@ cl->magic = HTB_CMAGIC; #endif - /* create leaf qdisc early because it uses kmalloc(GPF_KERNEL) + /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) so that can't be used inside of sch_tree_lock -- thanks to Karlis Peisenieks */ new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); diff -urN linux-2.4.25/net/sched/sch_red.c linux-2.4.26/net/sched/sch_red.c --- linux-2.4.25/net/sched/sch_red.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_red.c 2004-04-14 06:05:41.000000000 -0700 @@ -41,9 +41,6 @@ #include #include -#define RED_ECN_ECT 0x02 -#define RED_ECN_CE 0x01 - /* Random Early Detection (RED) algorithm. ======================================= @@ -165,28 +162,16 @@ switch (skb->protocol) { case __constant_htons(ETH_P_IP): - { - u8 tos = skb->nh.iph->tos; - - if (!(tos & RED_ECN_ECT)) + if (!INET_ECN_is_capable(skb->nh.iph->tos)) return 0; - - if (!(tos & RED_ECN_CE)) + if (INET_ECN_is_not_ce(skb->nh.iph->tos)) IP_ECN_set_ce(skb->nh.iph); - return 1; - } - case __constant_htons(ETH_P_IPV6): - { - u32 label = *(u32*)skb->nh.raw; - - if (!(label & __constant_htonl(RED_ECN_ECT<<20))) + if (!INET_ECN_is_capable(ip6_get_dsfield(skb->nh.ipv6h))) return 0; - label |= __constant_htonl(RED_ECN_CE<<20); + IP6_ECN_set_ce(skb->nh.ipv6h); return 1; - } - default: return 0; } diff -urN linux-2.4.25/net/sched/sch_tbf.c linux-2.4.26/net/sched/sch_tbf.c --- linux-2.4.25/net/sched/sch_tbf.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sched/sch_tbf.c 2004-04-14 06:05:41.000000000 -0700 @@ -62,7 +62,7 @@ Algorithm. ---------- - + Let N(t_i) be B/R initially and N(t) grow continuously with time as: N(t+delta) = min{B/R, N(t) + delta} @@ -146,15 +146,15 @@ if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch)) #endif kfree_skb(skb); - + return NET_XMIT_DROP; } - + if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) { sch->stats.drops++; return ret; - } - + } + sch->q.qlen++; sch->stats.bytes += skb->len; sch->stats.packets++; @@ -165,10 +165,10 @@ { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; int ret; - + if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) - sch->q.qlen++; - + sch->q.qlen++; + return ret; } @@ -176,7 +176,7 @@ { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; unsigned int len; - + if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { sch->q.qlen--; sch->stats.drops++; @@ -196,7 +196,7 @@ { struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; struct sk_buff *skb; - + skb = q->qdisc->dequeue(q->qdisc); if (skb) { @@ -204,7 +204,7 @@ long toks; long ptoks = 0; unsigned int len = skb->len; - + PSCHED_GET_TIME(now); toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer, 0); @@ -248,13 +248,13 @@ This is the main idea of all FQ algorithms (cf. CSZ, HPFQ, HFSC) */ - + if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { - /* When requeue fails skb is dropped */ + /* When requeue fails skb is dropped */ sch->q.qlen--; sch->stats.drops++; - } - + } + sch->flags |= TCQ_F_THROTTLED; sch->stats.overlimits++; } @@ -279,24 +279,24 @@ struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops); struct rtattr *rta; int ret; - + if (q) { rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); if (rta) { rta->rta_type = RTM_NEWQDISC; - rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); + rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; - + ret = q->ops->change(q, rta); kfree(rta); - + if (ret == 0) return q; } qdisc_destroy(q); } - return NULL; + return NULL; } static int tbf_change(struct Qdisc* sch, struct rtattr *opt) @@ -340,7 +340,7 @@ } if (max_size < 0) goto done; - + if (q->qdisc == &noop_qdisc) { if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) goto done; @@ -370,19 +370,19 @@ { int err; struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; - + if (opt == NULL) return -EINVAL; - + MOD_INC_USE_COUNT; - + PSCHED_GET_TIME(q->t_c); init_timer(&q->wd_timer); q->wd_timer.function = tbf_watchdog; q->wd_timer.data = (unsigned long)sch; q->qdisc = &noop_qdisc; - + if ((err = tbf_change(sch, opt)) != 0) { MOD_DEC_USE_COUNT; } @@ -399,7 +399,7 @@ qdisc_put_rtab(q->P_tab); if (q->R_tab) qdisc_put_rtab(q->R_tab); - + qdisc_destroy(q->qdisc); q->qdisc = &noop_qdisc; @@ -412,10 +412,10 @@ unsigned char *b = skb->tail; struct rtattr *rta; struct tc_tbf_qopt opt; - + rta = (struct rtattr*)b; RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - + opt.limit = q->limit; opt.rate = q->R_tab->rate; if (q->P_tab) @@ -439,11 +439,10 @@ { struct tbf_sched_data *q = (struct tbf_sched_data*)sch->data; - if (cl != 1) /* only one class */ + if (cl != 1) /* only one class */ return -ENOENT; - - tcm->tcm_parent = TC_H_ROOT; - tcm->tcm_handle = 1; + + tcm->tcm_handle |= TC_H_MIN(1); tcm->tcm_info = q->qdisc->handle; return 0; @@ -457,12 +456,12 @@ if (new == NULL) new = &noop_qdisc; - sch_tree_lock(sch); + sch_tree_lock(sch); *old = xchg(&q->qdisc, new); qdisc_reset(*old); sch->q.qlen = 0; sch_tree_unlock(sch); - + return 0; } @@ -481,7 +480,7 @@ { } -static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, +static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **tca, unsigned long *arg) { return -ENOSYS; @@ -494,11 +493,9 @@ static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) { - struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data; - if (!walker->stop) { - if (walker->count >= walker->skip) - if (walker->fn(sch, (unsigned long)q, walker) < 0) { + if (walker->count >= walker->skip) + if (walker->fn(sch, 1, walker) < 0) { walker->stop = 1; return; } @@ -545,7 +542,7 @@ return register_qdisc(&tbf_qdisc_ops); } -void cleanup_module(void) +void cleanup_module(void) { unregister_qdisc(&tbf_qdisc_ops); } diff -urN linux-2.4.25/net/sctp/Config.in linux-2.4.26/net/sctp/Config.in --- linux-2.4.25/net/sctp/Config.in 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/Config.in 2004-04-14 06:05:41.000000000 -0700 @@ -4,17 +4,40 @@ mainmenu_option next_comment comment ' SCTP Configuration (EXPERIMENTAL)' -if [ "$CONFIG_IPV6" != "n" ]; then - define_bool CONFIG_IPV6_SCTP__ $CONFIG_IPV6 -else - define_bool CONFIG_IPV6_SCTP__ y +tristate ' The SCTP Protocol (EXPERIMENTAL)' CONFIG_IP_SCTP + +if [ "$CONFIG_IP_SCTP" = "y" -a "$CONFIG_IPV6" = "m" ]; then + define_tristate CONFIG_IP_SCTP m fi -dep_tristate ' The SCTP Protocol (EXPERIMENTAL)' CONFIG_IP_SCTP $CONFIG_IPV6_SCTP__ if [ "$CONFIG_IP_SCTP" != "n" ]; then - bool ' SCTP: Use old checksum (Adler-32)' CONFIG_SCTP_ADLER32 - bool ' SCTP: Debug messages' CONFIG_SCTP_DBG_MSG - bool ' SCTP: Debug object counts' CONFIG_SCTP_DBG_OBJCNT + bool ' SCTP: Debug messages' CONFIG_SCTP_DBG_MSG + bool ' SCTP: Debug object counts' CONFIG_SCTP_DBG_OBJCNT + if [ "$CONFIG_CRYPTO_HMAC" = "n" ]; then + choice ' SCTP: Cookie HMAC Algorithm' \ + "HMAC-NONE CONFIG_SCTP_HMAC_NONE" HMAC-NONE + else + if [ "$CONFIG_CRYPTO_MD5" = "n" -a "$CONFIG_CRYPTO_SHA1" = "n" ]; then + choice ' SCTP: Cookie HMAC Algorithm' \ + "HMAC-NONE CONFIG_SCTP_HMAC_NONE" HMAC-NONE + else + if [ "$CONFIG_CRYPTO_MD5" != "n" -a "$CONFIG_CRYPTO_SHA1" != "n" ]; then + choice ' SCTP: Cookie HMAC Algorithm' \ + "HMAC-NONE CONFIG_SCTP_HMAC_NONE \ + HMAC-SHA1 CONFIG_SCTP_HMAC_SHA1 \ + HMAC-MD5 CONFIG_SCTP_HMAC_MD5" HMAC-MD5 + else + if [ "$CONFIG_CRYPTO_MD5" != "n" ]; then + choice 'SCTP: Cookie HMAC Algorithm' \ + "HMAC-NONE CONFIG_SCTP_HMAC_NONE \ + HMAC-MD5 CONFIG_SCTP_HMAC_MD5" HMAC-MD5 + else + choice 'SCTP: Cookie HMAC Algorithm' \ + "HMAC-NONE CONFIG_SCTP_HMAC_NONE \ + HMAC-SHA1 CONFIG_SCTP_HMAC_SHA1" HMAC-SHA1 + fi + fi + fi + fi fi - endmenu diff -urN linux-2.4.25/net/sctp/Makefile linux-2.4.26/net/sctp/Makefile --- linux-2.4.25/net/sctp/Makefile 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/Makefile 2004-04-14 06:05:41.000000000 -0700 @@ -6,16 +6,11 @@ obj-$(CONFIG_IP_SCTP) += sctp.o -obj-y := endpointola.o output.o sm_make_chunk.o associola.o hashdriver.o \ +obj-y := endpointola.o output.o sm_make_chunk.o associola.o \ outqueue.o sm_sideeffect.o transport.o bind_addr.o input.o primitive.o \ sm_statefuns.o tsnmap.o command.o inqueue.o proc.o sm_statetable.o \ - ulpevent.o protocol.o socket.o ulpqueue.o debug.o sla1.o ssnmap.o - -ifeq ($(CONFIG_SCTP_ADLER32), y) -obj-y += adler32.o -else -obj-y += crc32c.o -endif + ulpevent.o protocol.o socket.o ulpqueue.o debug.o ssnmap.o \ + crc32c.o chunk.o obj-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o obj-$(CONFIG_SYSCTL) += sysctl.o diff -urN linux-2.4.25/net/sctp/associola.c linux-2.4.26/net/sctp/associola.c --- linux-2.4.25/net/sctp/associola.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sctp/associola.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 La Monte H.P. Yarroll * @@ -41,6 +41,8 @@ * Hui Huang * Sridhar Samudrala * Daisy Chang + * Ryan Layer + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -97,7 +99,6 @@ int gfp) { struct sctp_opt *sp; - struct sctp_protocol *proto = sctp_get_protocol(); int i; /* Retrieve the SCTP per socket area. */ @@ -127,29 +128,30 @@ asoc->base.addr_lock = RW_LOCK_UNLOCKED; asoc->state = SCTP_STATE_CLOSED; - asoc->state_timestamp = jiffies; - - /* Set things that have constant value. */ - asoc->cookie_life.tv_sec = sctp_proto.valid_cookie_life / HZ; - asoc->cookie_life.tv_usec = (sctp_proto.valid_cookie_life % HZ) * - 1000000L / HZ; + /* Set these values from the socket values, a conversion between + * millsecons to seconds/microseconds must also be done. + */ + asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000; + asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) + * 1000; asoc->pmtu = 0; asoc->frag_point = 0; - /* Initialize the default association max_retrans and RTO values. */ - asoc->max_retrans = proto->max_retrans_association; - asoc->rto_initial = proto->rto_initial; - asoc->rto_max = proto->rto_max; - asoc->rto_min = proto->rto_min; + /* Set the association max_retrans and RTO values from the + * socket values. + */ + asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; + asoc->rto_initial = SCTP_MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial); + asoc->rto_max = SCTP_MSECS_TO_JIFFIES(sp->rtoinfo.srto_max); + asoc->rto_min = SCTP_MSECS_TO_JIFFIES(sp->rtoinfo.srto_min); - asoc->overall_error_threshold = 0; asoc->overall_error_count = 0; /* Initialize the maximum mumber of new data packets that can be sent * in a burst. */ - asoc->max_burst = proto->max_burst; + asoc->max_burst = sctp_max_burst; /* Copy things from the endpoint. */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { @@ -166,7 +168,9 @@ asoc->c.sinit_max_instreams = sp->initmsg.sinit_max_instreams; asoc->c.sinit_num_ostreams = sp->initmsg.sinit_num_ostreams; asoc->max_init_attempts = sp->initmsg.sinit_max_attempts; - asoc->max_init_timeo = sp->initmsg.sinit_max_init_timeo * HZ; + + asoc->max_init_timeo = + SCTP_MSECS_TO_JIFFIES(sp->initmsg.sinit_max_init_timeo); /* Allocate storage for the ssnmap after the inbound and outbound * streams have been negotiated during Init. @@ -178,10 +182,10 @@ * RFC 6 - A SCTP receiver MUST be able to receive a minimum of * 1500 bytes in one SCTP packet. */ - if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) + if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW) asoc->rwnd = SCTP_DEFAULT_MINWINDOW; else - asoc->rwnd = sk->rcvbuf; + asoc->rwnd = sk->sk_rcvbuf; asoc->a_rwnd = asoc->rwnd; @@ -220,12 +224,14 @@ * remote endpoint it should do the following: * ... * A2) a serial number should be assigned to the chunk. The serial - * number should be a monotonically increasing number. All serial - * numbers are defined to be initialized at the start of the + * number SHOULD be a monotonically increasing number. The serial + * numbers SHOULD be initialized at the start of the * association to the same value as the initial TSN. */ asoc->addip_serial = asoc->c.initial_tsn; + skb_queue_head_init(&asoc->addip_chunks); + /* Make an empty list of remote transport addresses. */ INIT_LIST_HEAD(&asoc->peer.transport_addr_list); @@ -242,6 +248,11 @@ */ asoc->peer.sack_needed = 1; + /* Assume that the peer recongizes ASCONF until reported otherwise + * via an ERROR chunk. + */ + asoc->peer.asconf_capable = 1; + /* Create an input queue. */ sctp_inq_init(&asoc->base.inqueue); sctp_inq_set_th_handler(&asoc->base.inqueue, @@ -257,17 +268,14 @@ sctp_packet_transmit_chunk, sctp_packet_transmit); - if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc)) + if (!sctp_ulpq_init(&asoc->ulpq, asoc)) goto fail_init; /* Set up the tsn tracking. */ sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0); - skb_queue_head_init(&asoc->addip_chunks); - asoc->need_ecne = 0; - asoc->debug_name = "unnamedasoc"; asoc->eyecatcher = SCTP_ASSOC_EYECATCHER; /* Assume that peer would support both address types unless we are @@ -279,6 +287,12 @@ asoc->autoclose = sp->autoclose; + asoc->default_stream = sp->default_stream; + asoc->default_ppid = sp->default_ppid; + asoc->default_flags = sp->default_flags; + asoc->default_context = sp->default_context; + asoc->default_timetolive = sp->default_timetolive; + return asoc; fail_init: @@ -300,9 +314,8 @@ list_del(&asoc->asocs); /* Decrement the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) - sk->ack_backlog--; + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + sk->sk_ack_backlog--; /* Mark as dead, so other users can know this structure is * going away. @@ -349,6 +362,14 @@ asoc->eyecatcher = 0; + /* Free any cached ASCONF_ACK chunk. */ + if (asoc->addip_last_asconf_ack) + sctp_chunk_free(asoc->addip_last_asconf_ack); + + /* Free any cached ASCONF chunk. */ + if (asoc->addip_last_asconf) + sctp_chunk_free(asoc->addip_last_asconf); + sctp_association_put(asoc); } @@ -381,6 +402,30 @@ */ if (transport->active) asoc->peer.active_path = transport; + + /* + * SFR-CACC algorithm: + * Upon the receipt of a request to change the primary + * destination address, on the data structure for the new + * primary destination, the sender MUST do the following: + * + * 1) If CHANGEOVER_ACTIVE is set, then there was a switch + * to this destination address earlier. The sender MUST set + * CYCLING_CHANGEOVER to indicate that this switch is a + * double switch to the same destination address. + */ + if (transport->cacc.changeover_active) + transport->cacc.cycling_changeover = 1; + + /* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that + * a changeover has occurred. + */ + transport->cacc.changeover_active = 1; + + /* 3) The sender MUST store the next TSN to be sent in + * next_tsn_at_change. + */ + transport->cacc.next_tsn_at_change = asoc->next_tsn; } /* Add a transport address to an association. */ @@ -392,13 +437,14 @@ struct sctp_opt *sp; unsigned short port; + sp = sctp_sk(asoc->base.sk); + /* AF_INET and AF_INET6 share common port field. */ port = addr->v4.sin_port; /* Set the port if it has not been set yet. */ - if (0 == asoc->peer.port) { + if (0 == asoc->peer.port) asoc->peer.port = port; - } /* Check to see if this is a duplicate. */ peer = sctp_assoc_lookup_paddr(asoc, addr); @@ -427,7 +473,7 @@ SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " "%d\n", asoc, asoc->pmtu); - asoc->frag_point = sctp_frag_point(asoc->pmtu); + asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); /* The asoc->peer.port might not be meaningful yet, but * initialize the packet structure anyway. @@ -456,30 +502,27 @@ peer->partial_bytes_acked = 0; peer->flight_size = 0; - peer->error_threshold = peer->max_retrans; - /* Update the overall error threshold value of the association - * taking the new peer's error threshold into account. - */ - asoc->overall_error_threshold = - min(asoc->overall_error_threshold + peer->error_threshold, - asoc->max_retrans); - /* By default, enable heartbeat for peer address. */ peer->hb_allowed = 1; /* Initialize the peer's heartbeat interval based on the * sock configured value. */ - sp = sctp_sk(asoc->base.sk); - peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ; + peer->hb_interval = SCTP_MSECS_TO_JIFFIES(sp->paddrparam.spp_hbinterval); + + /* Set the path max_retrans. */ + peer->max_retrans = asoc->max_retrans; + + /* Set the transport's RTO.initial value */ + peer->rto = asoc->rto_initial; /* Attach the remote transport to our asoc. */ list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); /* If we do not yet have a primary path, set one. */ - if (NULL == asoc->peer.primary_path) { + if (!asoc->peer.primary_path) { sctp_assoc_set_primary(asoc, peer); asoc->peer.retran_path = peer; } @@ -490,6 +533,45 @@ return peer; } +/* Delete a transport address from an association. */ +void sctp_assoc_del_peer(struct sctp_association *asoc, + const union sctp_addr *addr) +{ + struct list_head *pos; + struct list_head *temp; + struct sctp_transport *peer = NULL; + struct sctp_transport *transport; + + list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { + transport = list_entry(pos, struct sctp_transport, transports); + if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) { + peer = transport; + list_del(pos); + break; + } + } + + /* The address we want delete is not in the association. */ + if (!peer) + return; + + /* Get the first transport of asoc. */ + pos = asoc->peer.transport_addr_list.next; + transport = list_entry(pos, struct sctp_transport, transports); + + /* Update any entries that match the peer to be deleted. */ + if (asoc->peer.primary_path == peer) + sctp_assoc_set_primary(asoc, transport); + if (asoc->peer.active_path == peer) + asoc->peer.active_path = transport; + if (asoc->peer.retran_path == peer) + asoc->peer.retran_path = transport; + if (asoc->peer.last_data_from == peer) + asoc->peer.last_data_from = transport; + + sctp_transport_free(peer); +} + /* Lookup a transport by address. */ struct sctp_transport *sctp_assoc_lookup_paddr( const struct sctp_association *asoc, @@ -528,13 +610,13 @@ /* Record the transition on the transport. */ switch (command) { case SCTP_TRANSPORT_UP: - transport->active = 1; - spc_state = ADDRESS_AVAILABLE; + transport->active = SCTP_ACTIVE; + spc_state = SCTP_ADDR_REACHABLE; break; case SCTP_TRANSPORT_DOWN: - transport->active = 0; - spc_state = ADDRESS_UNREACHABLE; + transport->active = SCTP_INACTIVE; + spc_state = SCTP_ADDR_UNREACHABLE; break; default: @@ -592,7 +674,7 @@ /* If we failed to find a usable transport, just camp on the * primary, even if it is inactive. */ - if (NULL == first) { + if (!first) { first = asoc->peer.primary_path; second = asoc->peer.primary_path; } @@ -665,7 +747,7 @@ * Note: We are sly and return a shared, prealloced chunk. FIXME: * No we don't, but we could/should. */ -sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc) +struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc) { struct sctp_chunk *chunk; @@ -683,7 +765,7 @@ /* Use this function for the packet prepend callback when no ECNE * packet is desired (e.g. some packets don't like to be bundled). */ -sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc) +struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc) { return NULL; } @@ -691,13 +773,14 @@ /* * Find which transport this TSN was sent on. */ -struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, __u32 tsn) +struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, + __u32 tsn) { struct sctp_transport *active; struct sctp_transport *match; struct list_head *entry, *pos; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 key = htonl(tsn); match = NULL; @@ -720,7 +803,7 @@ active = asoc->peer.active_path; list_for_each(entry, &active->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, transmitted_list); + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = active; @@ -735,7 +818,7 @@ if (transport == active) break; list_for_each(entry, &transport->transmitted) { - chunk = list_entry(entry, sctp_chunk_t, + chunk = list_entry(entry, struct sctp_chunk, transmitted_list); if (key == chunk->subh.data_hdr->tsn) { match = transport; @@ -773,15 +856,34 @@ return transport; } +/* Is this a live association structure. */ +int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc) +{ + + /* First, verify that this is a kernel address. */ + if (!sctp_is_valid_kaddr((unsigned long) asoc)) + return 0; + + /* Verify that this _is_ an sctp_association + * data structure and if so, that the socket matches. + */ + if (SCTP_ASSOC_EYECATCHER != asoc->eyecatcher) + return 0; + if (asoc->base.sk != sk) + return 0; + + /* The association is valid. */ + return 1; +} + /* Do delayed input processing. This is scheduled by sctp_rcv(). */ static void sctp_assoc_bh_rcv(struct sctp_association *asoc) { struct sctp_endpoint *ep; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sock *sk; struct sctp_inq *inqueue; int state, subtype; - sctp_assoc_t associd = sctp_assoc2id(asoc); int error = 0; /* The association should be held so we should be safe. */ @@ -811,7 +913,7 @@ /* Check to see if the association is freed in response to * the incoming chunk. If so, get out of the while loop. */ - if (!sctp_id2assoc(sk, associd)) + if (!sctp_assoc_valid(sk, asoc)) break; /* If there is an error on chunk, discard this packet. */ @@ -830,11 +932,11 @@ /* Delete the association from the old endpoint's list of * associations. */ - list_del(&assoc->asocs); + list_del_init(&assoc->asocs); /* Decrement the backlog value for a TCP-style socket. */ - if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type) - oldsk->ack_backlog--; + if (sctp_style(oldsk, TCP)) + oldsk->sk_ack_backlog--; /* Release references to the old endpoint and the sock. */ sctp_endpoint_put(assoc->ep); @@ -853,7 +955,8 @@ } /* Update an association (possibly from unexpected COOKIE-ECHO processing). */ -void sctp_assoc_update(struct sctp_association *asoc, struct sctp_association *new) +void sctp_assoc_update(struct sctp_association *asoc, + struct sctp_association *new) { /* Copy in new parameters of peer. */ asoc->c = new->c; @@ -875,7 +978,7 @@ * current next_tsn in case data sent to peer * has been discarded and needs retransmission. */ - if (SCTP_STATE_ESTABLISHED == asoc->state) { + if (sctp_state(asoc, ESTABLISHED)) { asoc->next_tsn = new->next_tsn; asoc->ctsn_ack_point = new->ctsn_ack_point; @@ -947,7 +1050,8 @@ } /* Choose the transport for sending a SHUTDOWN packet. */ -struct sctp_transport *sctp_assoc_choose_shutdown_transport(struct sctp_association *asoc) +struct sctp_transport *sctp_assoc_choose_shutdown_transport( + struct sctp_association *asoc) { /* If this is the first time SHUTDOWN is sent, use the active path, * else use the retran path. If the last SHUTDOWN was sent over the @@ -983,8 +1087,9 @@ } if (pmtu) { + struct sctp_opt *sp = sctp_sk(asoc->base.sk); asoc->pmtu = pmtu; - asoc->frag_point = sctp_frag_point(pmtu); + asoc->frag_point = sctp_frag_point(sp, pmtu); } SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", @@ -1000,7 +1105,7 @@ case SCTP_STATE_SHUTDOWN_RECEIVED: if ((asoc->rwnd > asoc->a_rwnd) && ((asoc->rwnd - asoc->a_rwnd) >= - min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) + min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) return 1; break; default: @@ -1010,9 +1115,9 @@ } /* Increase asoc's rwnd by len and send any window update SACK if needed. */ -void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len) +void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) { - sctp_chunk_t *sack; + struct sctp_chunk *sack; struct timer_list *timer; if (asoc->rwnd_over) { @@ -1056,7 +1161,7 @@ } /* Decrease asoc's rwnd by len. */ -void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len) +void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) { SCTP_ASSERT(asoc->rwnd, "rwnd zero", return); SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return); @@ -1083,7 +1188,7 @@ * the endpoint. */ scope = sctp_scope(&asoc->peer.active_path->ipaddr); - flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0; if (asoc->peer.ipv4_address) flags |= SCTP_ADDR4_PEERSUPP; if (asoc->peer.ipv6_address) @@ -1096,12 +1201,32 @@ /* Build the association's bind address list from the cookie. */ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc, - sctp_cookie_t *cookie, int gfp) + struct sctp_cookie *cookie, int gfp) { int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length); int var_size3 = cookie->raw_addr_list_len; - __u8 *raw = (__u8 *)cookie + sizeof(sctp_cookie_t) + var_size2; + __u8 *raw = (__u8 *)cookie + sizeof(struct sctp_cookie) + var_size2; return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3, asoc->ep->base.bind_addr.port, gfp); } + +/* Lookup laddr in the bind address list of an association. */ +int sctp_assoc_lookup_laddr(struct sctp_association *asoc, + const union sctp_addr *laddr) +{ + int found; + + sctp_read_lock(&asoc->base.addr_lock); + if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) && + sctp_bind_addr_match(&asoc->base.bind_addr, laddr, + sctp_sk(asoc->base.sk))) { + found = 1; + goto out; + } + + found = 0; +out: + sctp_read_unlock(&asoc->base.addr_lock); + return found; +} diff -urN linux-2.4.25/net/sctp/bind_addr.c linux-2.4.26/net/sctp/bind_addr.c --- linux-2.4.25/net/sctp/bind_addr.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/bind_addr.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) Cisco 1999,2000 * Copyright (c) Motorola 1999,2000,2001 - * Copyright (c) International Business Machines Corp., 2001,2002 * Copyright (c) La Monte H.P. Yarroll 2001 * * This file is part of the SCTP kernel reference implementation. @@ -52,19 +52,20 @@ #include /* Forward declarations for internal helpers. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *, +static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *, sctp_scope_t scope, int gfp, int flags); -static void sctp_bind_addr_clean(sctp_bind_addr_t *); +static void sctp_bind_addr_clean(struct sctp_bind_addr *); /* First Level Abstractions. */ /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses * in 'src' which have a broader scope than 'scope'. */ -int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, +int sctp_bind_addr_copy(struct sctp_bind_addr *dest, + const struct sctp_bind_addr *src, sctp_scope_t scope, int gfp, int flags) { - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; struct list_head *pos; int error = 0; @@ -73,7 +74,7 @@ /* Extract the addresses which are relevant for this scope. */ list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + addr = list_entry(pos, struct sctp_sockaddr_entry, list); error = sctp_copy_one_addr(dest, &addr->a, scope, gfp, flags); if (error < 0) @@ -86,7 +87,7 @@ */ if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, + addr = list_entry(pos, struct sctp_sockaddr_entry, list); error = sctp_copy_one_addr(dest, &addr->a, SCTP_SCOPE_LINK, gfp, @@ -104,11 +105,11 @@ } /* Create a new SCTP_bind_addr from nothing. */ -sctp_bind_addr_t *sctp_bind_addr_new(int gfp) +struct sctp_bind_addr *sctp_bind_addr_new(int gfp) { - sctp_bind_addr_t *retval; + struct sctp_bind_addr *retval; - retval = t_new(sctp_bind_addr_t, gfp); + retval = t_new(struct sctp_bind_addr, gfp); if (!retval) goto nomem; @@ -123,7 +124,7 @@ /* Initialize the SCTP_bind_addr structure for either an endpoint or * an association. */ -void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port) +void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port) { bp->malloced = 0; @@ -132,14 +133,14 @@ } /* Dispose of the address list. */ -static void sctp_bind_addr_clean(sctp_bind_addr_t *bp) +static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; struct list_head *pos, *temp; /* Empty the bind address list. */ list_for_each_safe(pos, temp, &bp->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + addr = list_entry(pos, struct sctp_sockaddr_entry, list); list_del(pos); kfree(addr); SCTP_DBG_OBJCNT_DEC(addr); @@ -147,7 +148,7 @@ } /* Dispose of an SCTP_bind_addr structure */ -void sctp_bind_addr_free(sctp_bind_addr_t *bp) +void sctp_bind_addr_free(struct sctp_bind_addr *bp) { /* Empty the bind address list. */ sctp_bind_addr_clean(bp); @@ -159,17 +160,17 @@ } /* Add an address to the bind address list in the SCTP_bind_addr structure. */ -int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new, +int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, int gfp) { - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; /* Add the address to the bind address list. */ - addr = t_new(struct sockaddr_storage_list, gfp); + addr = t_new(struct sctp_sockaddr_entry, gfp); if (!addr) return -ENOMEM; - addr->a = *new; + memcpy(&addr->a, new, sizeof(*new)); /* Fix up the port if it has not yet been set. * Both v4 and v6 have the port at the same offset. @@ -187,13 +188,13 @@ /* Delete an address from the bind address list in the SCTP_bind_addr * structure. */ -int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr) +int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr) { struct list_head *pos, *temp; - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; list_for_each_safe(pos, temp, &bp->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + addr = list_entry(pos, struct sctp_sockaddr_entry, list); if (sctp_cmp_addr_exact(&addr->a, del_addr)) { /* Found the exact match. */ list_del(pos); @@ -212,28 +213,30 @@ * * The second argument is the return value for the length. */ -union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, +union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, int *addrs_len, int gfp) { union sctp_params addrparms; union sctp_params retval; int addrparms_len; - sctp_addr_param_t rawaddr; + union sctp_addr_param rawaddr; int len; - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; struct list_head *pos; + struct sctp_af *af; + addrparms_len = 0; len = 0; /* Allocate enough memory at once. */ list_for_each(pos, &bp->address_list) { - len += sizeof(sctp_addr_param_t); + len += sizeof(union sctp_addr_param); } /* Don't even bother embedding an address if there * is only one. */ - if (len == sizeof(sctp_addr_param_t)) { + if (len == sizeof(union sctp_addr_param)) { retval.v = NULL; goto end_raw; } @@ -245,8 +248,9 @@ addrparms = retval; list_for_each(pos, &bp->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); - len = sockaddr2sctp_addr(&addr->a, &rawaddr); + addr = list_entry(pos, struct sctp_sockaddr_entry, list); + af = sctp_get_af_specific(addr->a.v4.sin_family); + len = af->to_addr_param(&addr->a, &rawaddr); memcpy(addrparms.v, &rawaddr, len); addrparms.v += len; addrparms_len += len; @@ -261,42 +265,39 @@ * Create an address list out of the raw address list format (IPv4 and IPv6 * address parameters). */ -int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, +int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, int addrs_len, __u16 port, int gfp) { - sctp_addr_param_t *rawaddr; - sctp_paramhdr_t *param; + union sctp_addr_param *rawaddr; + struct sctp_paramhdr *param; union sctp_addr addr; int retval = 0; int len; + struct sctp_af *af; /* Convert the raw address to standard address format */ while (addrs_len) { - param = (sctp_paramhdr_t *)raw_addr_list; - rawaddr = (sctp_addr_param_t *)raw_addr_list; + param = (struct sctp_paramhdr *)raw_addr_list; + rawaddr = (union sctp_addr_param *)raw_addr_list; - switch (param->type) { - case SCTP_PARAM_IPV4_ADDRESS: - case SCTP_PARAM_IPV6_ADDRESS: - sctp_param2sockaddr(&addr, rawaddr, port, 0); - retval = sctp_add_bind_addr(bp, &addr, gfp); - if (retval) { - /* Can't finish building the list, clean up. */ - sctp_bind_addr_clean(bp); - break;; - } - len = ntohs(param->length); - addrs_len -= len; - raw_addr_list += len; - break; - default: - /* Corrupted raw addr list! */ + af = sctp_get_af_specific(param_type2af(param->type)); + if (unlikely(!af)) { retval = -EINVAL; sctp_bind_addr_clean(bp); break; } - if (retval) - break; + + af->from_addr_param(&addr, rawaddr, port, 0); + retval = sctp_add_bind_addr(bp, &addr, gfp); + if (retval) { + /* Can't finish building the list, clean up. */ + sctp_bind_addr_clean(bp); + break;; + } + + len = ntohs(param->length); + addrs_len -= len; + raw_addr_list += len; } return retval; @@ -307,14 +308,15 @@ ********************************************************************/ /* Does this contain a specified address? Allow wildcarding. */ -int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr, +int sctp_bind_addr_match(struct sctp_bind_addr *bp, + const union sctp_addr *addr, struct sctp_opt *opt) { - struct sockaddr_storage_list *laddr; + struct sctp_sockaddr_entry *laddr; struct list_head *pos; list_for_each(pos, &bp->address_list) { - laddr = list_entry(pos, struct sockaddr_storage_list, list); + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); if (opt->pf->cmp_addr(&laddr->a, addr, opt)) return 1; } @@ -322,16 +324,52 @@ return 0; } +/* Find the first address in the bind address list that is not present in + * the addrs packed array. + */ +union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, + const union sctp_addr *addrs, + int addrcnt, + struct sctp_opt *opt) +{ + struct sctp_sockaddr_entry *laddr; + union sctp_addr *addr; + void *addr_buf; + struct sctp_af *af; + struct list_head *pos; + int i; + + list_for_each(pos, &bp->address_list) { + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); + + addr_buf = (union sctp_addr *)addrs; + for (i = 0; i < addrcnt; i++) { + addr = (union sctp_addr *)addr_buf; + af = sctp_get_af_specific(addr->v4.sin_family); + if (!af) + return NULL; + + if (opt->pf->cmp_addr(&laddr->a, addr, opt)) + break; + + addr_buf += af->sockaddr_len; + } + if (i == addrcnt) + return &laddr->a; + } + + return NULL; +} + /* Copy out addresses from the global local address list. */ -static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, +static int sctp_copy_one_addr(struct sctp_bind_addr *dest, + union sctp_addr *addr, sctp_scope_t scope, int gfp, int flags) { - struct sctp_protocol *proto = sctp_get_protocol(); int error = 0; if (sctp_is_any(addr)) { - error = sctp_copy_local_addr_list(proto, dest, scope, - gfp, flags); + error = sctp_copy_local_addr_list(dest, scope, gfp, flags); } else if (sctp_in_scope(addr, scope)) { /* Now that the address is in scope, check to see if * the address type is supported by local sock as diff -urN linux-2.4.25/net/sctp/chunk.c linux-2.4.26/net/sctp/chunk.c --- linux-2.4.25/net/sctp/chunk.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.26/net/sctp/chunk.c 2004-04-14 06:05:41.000000000 -0700 @@ -0,0 +1,323 @@ +/* SCTP kernel reference Implementation + * Copyright (c) 2003 International Business Machines Corp. + * + * This file is part of the SCTP kernel reference Implementation + * + * This file contains the code relating the the chunk abstraction. + * + * The SCTP reference implementation 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. + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * Jon Grimm + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* This file is mostly in anticipation of future work, but initially + * populate with fragment tracking for an outbound message. + */ + +/* Initialize datamsg from memory. */ +void sctp_datamsg_init(struct sctp_datamsg *msg) +{ + atomic_set(&msg->refcnt, 1); + msg->send_failed = 0; + msg->send_error = 0; + msg->can_expire = 0; + INIT_LIST_HEAD(&msg->chunks); +} + +/* Allocate and initialize datamsg. */ +struct sctp_datamsg *sctp_datamsg_new(int gfp) +{ + struct sctp_datamsg *msg; + msg = kmalloc(sizeof(struct sctp_datamsg), gfp); + if (msg) + sctp_datamsg_init(msg); + SCTP_DBG_OBJCNT_INC(datamsg); + return msg; +} + +/* Final destructruction of datamsg memory. */ +static void sctp_datamsg_destroy(struct sctp_datamsg *msg) +{ + struct list_head *pos, *temp; + struct sctp_chunk *chunk; + struct sctp_opt *sp; + struct sctp_ulpevent *ev; + struct sctp_association *asoc = NULL; + int error = 0, notify; + + /* If we failed, we may need to notify. */ + notify = msg->send_failed ? -1 : 0; + + /* Release all references. */ + list_for_each_safe(pos, temp, &msg->chunks) { + list_del_init(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + /* Check whether we _really_ need to notify. */ + if (notify < 0) { + asoc = chunk->asoc; + if (msg->send_error) + error = msg->send_error; + else + error = asoc->outqueue.error; + + sp = sctp_sk(asoc->base.sk); + notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED, + &sp->subscribe); + } + + /* Generate a SEND FAILED event only if enabled. */ + if (notify > 0) { + int sent; + if (chunk->has_tsn) + sent = SCTP_DATA_SENT; + else + sent = SCTP_DATA_UNSENT; + + ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, + error, GFP_ATOMIC); + if (ev) + sctp_ulpq_tail_event(&asoc->ulpq, ev); + } + + sctp_chunk_put(chunk); + } + + SCTP_DBG_OBJCNT_DEC(datamsg); + kfree(msg); +} + +/* Hold a reference. */ +void sctp_datamsg_hold(struct sctp_datamsg *msg) +{ + atomic_inc(&msg->refcnt); +} + +/* Release a reference. */ +void sctp_datamsg_put(struct sctp_datamsg *msg) +{ + if (atomic_dec_and_test(&msg->refcnt)) + sctp_datamsg_destroy(msg); +} + +/* Free a message. Really just give up a reference, the + * really free happens in sctp_datamsg_destroy(). + */ +void sctp_datamsg_free(struct sctp_datamsg *msg) +{ + sctp_datamsg_put(msg); +} + +/* Hold on to all the fragments until all chunks have been sent. */ +void sctp_datamsg_track(struct sctp_chunk *chunk) +{ + sctp_chunk_hold(chunk); +} + +/* Assign a chunk to this datamsg. */ +void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk) +{ + sctp_datamsg_hold(msg); + chunk->msg = msg; +} + + +/* A data chunk can have a maximum payload of (2^16 - 20). Break + * down any such message into smaller chunks. Opportunistically, fragment + * the chunks down to the current MTU constraints. We may get refragmented + * later if the PMTU changes, but it is _much better_ to fragment immediately + * with a reasonable guess than always doing our fragmentation on the + * soft-interrupt. + */ +struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, + struct sctp_sndrcvinfo *sinfo, + struct msghdr *msgh, int msg_len) +{ + int max, whole, i, offset, over, err; + int len, first_len; + struct sctp_chunk *chunk; + struct sctp_datamsg *msg; + struct list_head *pos, *temp; + __u8 frag; + + msg = sctp_datamsg_new(GFP_KERNEL); + if (!msg) + return NULL; + + /* Note: Calculate this outside of the loop, so that all fragments + * have the same expiration. + */ + if (sinfo->sinfo_timetolive) { + /* sinfo_timetolive is in milliseconds */ + msg->expires_at = jiffies + + SCTP_MSECS_TO_JIFFIES(sinfo->sinfo_timetolive); + msg->can_expire = 1; + } + + /* What is a reasonable fragmentation point right now? */ + max = asoc->pmtu; + if (max < SCTP_MIN_PMTU) + max = SCTP_MIN_PMTU; + max -= SCTP_IP_OVERHEAD; + + /* Make sure not beyond maximum chunk size. */ + if (max > SCTP_MAX_CHUNK_LEN) + max = SCTP_MAX_CHUNK_LEN; + + /* Subtract out the overhead of a data chunk header. */ + max -= sizeof(struct sctp_data_chunk); + whole = 0; + + /* If user has specified smaller fragmentation, make it so. */ + if (sctp_sk(asoc->base.sk)->user_frag) + max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag); + + first_len = max; + + /* Encourage Cookie-ECHO bundling. */ + if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { + whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); + + /* Account for the DATA to be bundled with the COOKIE-ECHO. */ + if (whole) { + first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; + msg_len -= first_len; + whole = 1; + } + } + + /* How many full sized? How many bytes leftover? */ + whole += msg_len / max; + over = msg_len % max; + offset = 0; + + if ((whole > 1) || (whole && over)) + SCTP_INC_STATS_USER(SctpFragUsrMsgs); + + /* Create chunks for all the full sized DATA chunks. */ + for (i=0, len=first_len; i < whole; i++) { + frag = SCTP_DATA_MIDDLE_FRAG; + + if (0 == i) + frag |= SCTP_DATA_FIRST_FRAG; + + if ((i == (whole - 1)) && !over) + frag |= SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); + + if (!chunk) + goto errout; + err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov); + if (err < 0) + goto errout; + + offset += len; + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + + /* The first chunk, the first chunk was likely short + * to allow bundling, so reset to full size. + */ + if (0 == i) + len = max; + } + + /* .. now the leftover bytes. */ + if (over) { + if (!whole) + frag = SCTP_DATA_NOT_FRAG; + else + frag = SCTP_DATA_LAST_FRAG; + + chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); + + if (!chunk) + goto errout; + + err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov); + + /* Put the chunk->skb back into the form expected by send. */ + __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr + - (__u8 *)chunk->skb->data); + if (err < 0) + goto errout; + + sctp_datamsg_assign(msg, chunk); + list_add_tail(&chunk->frag_list, &msg->chunks); + } + + return msg; + +errout: + list_for_each_safe(pos, temp, &msg->chunks) { + list_del_init(pos); + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_chunk_free(chunk); + } + sctp_datamsg_free(msg); + return NULL; +} + +/* Check whether this message has expired. */ +int sctp_datamsg_expires(struct sctp_chunk *chunk) +{ + struct sctp_datamsg *msg = chunk->msg; + + /* FIXME: When PR-SCTP is supported we can make this + * check more lenient. + */ + if (!msg->can_expire) + return 0; + + if (time_after(jiffies, msg->expires_at)) + return 1; + + return 0; +} + +/* This chunk (and consequently entire message) has failed in its sending. */ +void sctp_datamsg_fail(struct sctp_chunk *chunk, int error) +{ + chunk->msg->send_failed = 1; + chunk->msg->send_error = error; +} diff -urN linux-2.4.25/net/sctp/debug.c linux-2.4.26/net/sctp/debug.c --- linux-2.4.25/net/sctp/debug.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/debug.c 2004-04-14 06:05:41.000000000 -0700 @@ -185,6 +185,7 @@ "TIMEOUT_T1_INIT", "TIMEOUT_T2_SHUTDOWN", "TIMEOUT_T3_RTX", + "TIMEOUT_T4_RTO", "TIMEOUT_T5_SHUTDOWN_GUARD", "TIMEOUT_HEARTBEAT", "TIMEOUT_SACK", diff -urN linux-2.4.25/net/sctp/endpointola.c linux-2.4.26/net/sctp/endpointola.c --- linux-2.4.25/net/sctp/endpointola.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/endpointola.c 2004-04-14 06:05:41.000000000 -0700 @@ -54,6 +54,7 @@ #include #include #include /* get_random_bytes() */ +#include #include #include #include @@ -128,15 +129,16 @@ ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = SCTP_DEFAULT_TIMEOUT_T1_INIT; ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = - sp->rtoinfo.srto_initial; + SCTP_MSECS_TO_JIFFIES(sp->rtoinfo.srto_initial); ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; /* sctpimpguide-05 Section 2.12.2 * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the * recommended value of 5 times 'RTO.Max'. */ ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] - = 5 * sp->rtoinfo.srto_max; + = 5 * SCTP_MSECS_TO_JIFFIES(sp->rtoinfo.srto_max); ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; @@ -145,17 +147,9 @@ ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; - /* Set up the default send/receive buffer space. */ - - /* FIXME - Should the min and max window size be configurable - * sysctl parameters as opposed to be constants? - */ - sk->rcvbuf = SCTP_DEFAULT_MAXWINDOW; - sk->sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; - /* Use SCTP specific send buffer space queues. */ - sk->write_space = sctp_write_space; - sk->use_write_queue = 1; + sk->sk_write_space = sctp_write_space; + sk->sk_use_write_queue = 1; /* Initialize the secret key used with cookie. */ get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); @@ -176,9 +170,8 @@ list_add_tail(&asoc->asocs, &ep->asocs); /* Increment the backlog value for a TCP-style listening socket. */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state)) - sk->ack_backlog++; + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + sk->sk_ack_backlog++; } /* Free the endpoint structure. Delay cleanup until @@ -195,7 +188,7 @@ { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); - ep->base.sk->state = SCTP_SS_CLOSED; + ep->base.sk->sk_state = SCTP_SS_CLOSED; /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); @@ -313,13 +306,13 @@ const union sctp_addr *paddr) { struct list_head *pos; - struct sockaddr_storage_list *addr; - sctp_bind_addr_t *bp; + struct sctp_sockaddr_entry *addr; + struct sctp_bind_addr *bp; sctp_read_lock(&ep->base.addr_lock); bp = &ep->base.bind_addr; list_for_each(pos, &bp->address_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + addr = list_entry(pos, struct sctp_sockaddr_entry, list); if (sctp_has_association(&addr->a, paddr)) { sctp_read_unlock(&ep->base.addr_lock); return 1; @@ -338,7 +331,7 @@ struct sctp_association *asoc; struct sock *sk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; sctp_subtype_t subtype; sctp_state_t state; diff -urN linux-2.4.25/net/sctp/input.c linux-2.4.26/net/sctp/input.c --- linux-2.4.25/net/sctp/input.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/input.c 2004-04-14 06:05:41.000000000 -0700 @@ -106,7 +106,7 @@ struct sctp_endpoint *ep = NULL; struct sctp_ep_common *rcvr; struct sctp_transport *transport = NULL; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctphdr *sh; union sctp_addr src; union sctp_addr dest; @@ -124,16 +124,16 @@ /* Pull up the IP and SCTP headers. */ __skb_pull(skb, skb->h.raw - skb->data); if (skb->len < sizeof(struct sctphdr)) - goto bad_packet; + goto discard_it; if (sctp_rcv_checksum(skb) < 0) - goto bad_packet; + goto discard_it; skb_pull(skb, sizeof(struct sctphdr)); family = ipver2af(skb->nh.iph->version); af = sctp_get_af_specific(family); if (unlikely(!af)) - goto bad_packet; + goto discard_it; /* Initialize local addresses for lookups. */ af->from_skb(&src, skb, 1); @@ -150,7 +150,7 @@ * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!af->addr_valid(&src) || !af->addr_valid(&dest)) + if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); @@ -180,7 +180,7 @@ ret = sk_filter(sk, skb, 1); if (ret) - goto discard_release; + goto discard_release; /* Create an SCTP packet structure. */ chunk = sctp_chunkify(skb, asoc, sk); @@ -223,9 +223,6 @@ sock_put(sk); return ret; -bad_packet: - SCTP_INC_STATS(SctpChecksumErrors); - discard_it: kfree_skb(skb); return ret; @@ -250,13 +247,13 @@ */ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_inq *inqueue; /* One day chunk will live inside the skb, but for * now this works. */ - chunk = (sctp_chunk_t *) skb; + chunk = (struct sctp_chunk *) skb; inqueue = &chunk->rcvr->inqueue; sctp_inq_push(inqueue, chunk); @@ -447,10 +444,10 @@ inet = inet_sk(sk); if (!sock_owned_by_user(sk) && inet->recverr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } else { /* Only an error on timeout */ - sk->err_soft = err; + sk->sk_err_soft = err; } out_unlock: @@ -503,9 +500,10 @@ goto discard; if (SCTP_CID_ERROR == ch->type) { - err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t)); - if (SCTP_ERROR_STALE_COOKIE == err->cause) - goto discard; + sctp_walk_errors(err, ch) { + if (SCTP_ERROR_STALE_COOKIE == err->cause) + goto discard; + } } ch = (sctp_chunkhdr_t *) ch_end; @@ -522,12 +520,12 @@ { struct sctp_ep_common **epp; struct sctp_ep_common *epb; - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; epb = &ep->base; epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); - head = &sctp_proto.ep_hashbucket[epb->hashent]; + head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); epp = &head->chain; @@ -550,14 +548,14 @@ /* Remove endpoint from the hash table. */ void __sctp_unhash_endpoint(struct sctp_endpoint *ep) { - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; struct sctp_ep_common *epb; epb = &ep->base; epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); - head = &sctp_proto.ep_hashbucket[epb->hashent]; + head = &sctp_ep_hashtable[epb->hashent]; sctp_write_lock(&head->lock); @@ -582,13 +580,13 @@ /* Look up an endpoint. */ struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) { - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; struct sctp_ep_common *epb; struct sctp_endpoint *ep; int hash; hash = sctp_ep_hashfn(laddr->v4.sin_port); - head = &sctp_proto.ep_hashbucket[hash]; + head = &sctp_ep_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { ep = sctp_ep(epb); @@ -619,14 +617,14 @@ { struct sctp_ep_common **epp; struct sctp_ep_common *epb; - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; epb = &asoc->base; /* Calculate which chain this entry will belong to. */ epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); - head = &sctp_proto.assoc_hashbucket[epb->hashent]; + head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); epp = &head->chain; @@ -649,7 +647,7 @@ /* Remove association from the hash table. */ void __sctp_unhash_established(struct sctp_association *asoc) { - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; struct sctp_ep_common *epb; epb = &asoc->base; @@ -657,7 +655,7 @@ epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); - head = &sctp_proto.assoc_hashbucket[epb->hashent]; + head = &sctp_assoc_hashtable[epb->hashent]; sctp_write_lock(&head->lock); @@ -677,7 +675,7 @@ const union sctp_addr *peer, struct sctp_transport **pt) { - sctp_hashbucket_t *head; + struct sctp_hashbucket *head; struct sctp_ep_common *epb; struct sctp_association *asoc; struct sctp_transport *transport; @@ -687,7 +685,7 @@ * have wildcards anyways. */ hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port); - head = &sctp_proto.assoc_hashbucket[hash]; + head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { asoc = sctp_assoc(epb); @@ -766,6 +764,8 @@ sctp_chunkhdr_t *ch; union sctp_params params; sctp_init_chunk_t *init; + struct sctp_transport *transport; + struct sctp_af *af; ch = (sctp_chunkhdr_t *) skb->data; @@ -800,12 +800,13 @@ sctp_walk_params(params, init, init_hdr.params) { /* Note: Ignoring hostname addresses. */ - if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) && - (SCTP_PARAM_IPV6_ADDRESS != params.p->type)) + af = sctp_get_af_specific(param_type2af(params.p->type)); + if (!af) continue; - sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source), 0); - asoc = __sctp_lookup_association(laddr, paddr, transportp); + af->from_addr_param(paddr, params.addr, ntohs(sh->source), 0); + + asoc = __sctp_lookup_association(laddr, paddr, &transport); if (asoc) return asoc; } diff -urN linux-2.4.25/net/sctp/inqueue.c linux-2.4.26/net/sctp/inqueue.c --- linux-2.4.25/net/sctp/inqueue.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/inqueue.c 2004-04-14 06:05:41.000000000 -0700 @@ -78,17 +78,17 @@ /* Release the memory associated with an SCTP inqueue. */ void sctp_inq_free(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Empty the queue. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in))) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in))) + sctp_chunk_free(chunk); /* If there is a packet which is currently being worked on, * free it as well. */ if (queue->in_progress) - sctp_free_chunk(queue->in_progress); + sctp_chunk_free(queue->in_progress); if (queue->malloced) { /* Dump the master memory segment. */ @@ -99,7 +99,7 @@ /* Put a new packet in an SCTP inqueue. * We assume that packet->sctp_hdr is set and in host byte order. */ -void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet) +void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet) { /* Directly call the packet handling routine. */ @@ -117,9 +117,9 @@ * WARNING: If you need to put the chunk on another queue, you need to * make a shallow copy (clone) of it. */ -sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue) +struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_chunkhdr_t *ch = NULL; /* The assumption is that we are safe to process the chunks @@ -133,7 +133,7 @@ if (chunk->singleton || chunk->end_of_packet || chunk->pdiscard) { - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); chunk = queue->in_progress = NULL; } else { /* Nothing to do. Next chunk in the packet, please. */ @@ -152,7 +152,7 @@ return NULL; chunk = queue->in_progress = - (sctp_chunk_t *) skb_dequeue(&queue->in); + (struct sctp_chunk *) skb_dequeue(&queue->in); /* This is the first chunk in the packet. */ chunk->singleton = 1; diff -urN linux-2.4.25/net/sctp/ipv6.c linux-2.4.26/net/sctp/ipv6.c --- linux-2.4.25/net/sctp/ipv6.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/ipv6.c 2004-04-14 06:05:41.000000000 -0700 @@ -2,6 +2,7 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2002-2003 International Business Machines, Corp. + * Copyright (c) 2002-2003 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -15,7 +16,7 @@ * * The SCTP reference implementation 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. * @@ -32,14 +33,15 @@ * http://www.sf.net/projects/lksctp * * Written or modified by: - * Le Yanqun + * Le Yanqun * Hui Huang * La Monte H.P. Yarroll * Sridhar Samudrala - * Jon Grimm + * Jon Grimm + * Ardelle Fan * * Based on: - * linux/net/ipv6/tcp_ipv6.c + * linux/net/ipv6/tcp_ipv6.c * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -61,6 +63,7 @@ #include #include #include +#include #include #include @@ -79,14 +82,14 @@ /* FIXME: This macro needs to be moved to a common header file. */ #define NIP6(addr) \ - ntohs((addr)->s6_addr16[0]), \ - ntohs((addr)->s6_addr16[1]), \ - ntohs((addr)->s6_addr16[2]), \ - ntohs((addr)->s6_addr16[3]), \ - ntohs((addr)->s6_addr16[4]), \ - ntohs((addr)->s6_addr16[5]), \ - ntohs((addr)->s6_addr16[6]), \ - ntohs((addr)->s6_addr16[7]) + ntohs((addr)->s6_addr16[0]), \ + ntohs((addr)->s6_addr16[1]), \ + ntohs((addr)->s6_addr16[2]), \ + ntohs((addr)->s6_addr16[3]), \ + ntohs((addr)->s6_addr16[4]), \ + ntohs((addr)->s6_addr16[5]), \ + ntohs((addr)->s6_addr16[6]), \ + ntohs((addr)->s6_addr16[7]) /* ICMP error handler. */ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, @@ -134,10 +137,10 @@ np = inet6_sk(sk); icmpv6_err_convert(type, code, &err); if (!sock_owned_by_user(sk) && np->recverr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } else { /* Only an error on timeout */ - sk->err_soft = err; + sk->sk_err_soft = err; } out_unlock: @@ -155,7 +158,9 @@ struct ipv6_pinfo *np = inet6_sk(sk); struct flowi fl; - fl.proto = sk->protocol; + memset(&fl, 0, sizeof(fl)); + + fl.proto = sk->sk_protocol; /* Fill in the dest address from the route entry passed with the skb * and the source address from the transport. @@ -168,20 +173,20 @@ if (ipv6_addr_type(fl.fl6_src) & IPV6_ADDR_LINKLOCAL) fl.oif = transport->saddr.v6.sin6_scope_id; else - fl.oif = sk->bound_dev_if; - fl.uli_u.ports.sport = (sk)->sport; + fl.oif = sk->sk_bound_dev_if; + fl.uli_u.ports.sport = sk->sport; fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port; if (np->opt && np->opt->srcrt) { struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; - fl.nl_u.ip6_u.daddr = rt0->addr; + fl.fl6_dst = rt0->addr; } SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), - NIP6(fl.fl6_dst)); + __FUNCTION__, skb, skb->len, + NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); SCTP_INC_STATS(SctpOutSCTPPacks); @@ -196,8 +201,13 @@ union sctp_addr *saddr) { struct dst_entry *dst; - struct flowi fl = { - .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } }; + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + fl.fl6_dst = &daddr->v6.sin6_addr; + if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) + fl.oif = daddr->v6.sin6_scope_id; + SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", __FUNCTION__, NIP6(fl.fl6_dst)); @@ -252,9 +262,9 @@ void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, union sctp_addr *saddr) { - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; - struct sockaddr_storage_list *laddr; + struct sctp_sockaddr_entry *laddr; struct list_head *pos; sctp_scope_t scope; union sctp_addr *baddr = NULL; @@ -283,7 +293,7 @@ */ sctp_read_lock(addr_lock); list_for_each(pos, &bp->address_list) { - laddr = list_entry(pos, struct sockaddr_storage_list, list); + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); if ((laddr->a.sa.sa_family == AF_INET6) && (scope <= sctp_scope(&laddr->a))) { bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); @@ -315,7 +325,7 @@ { struct inet6_dev *in6_dev; struct inet6_ifaddr *ifp; - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; read_lock(&addrconf_lock); if ((in6_dev = __in6_dev_get(dev)) == NULL) { @@ -326,7 +336,7 @@ read_lock(&in6_dev->lock); for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) { /* Add the address to the local list. */ - addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); + addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC); if (addr) { addr->a.v6.sin6_family = AF_INET6; addr->a.v6.sin6_port = 0; @@ -369,20 +379,62 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) { addr->v6.sin6_family = AF_INET6; - addr->v6.sin6_port = (sk)->num; + addr->v6.sin6_port = sk->num; addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr; } -/* Initialize sk->rcv_saddr from sctp_addr. */ +/* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->rcv_saddr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + } } -/* Initialize sk->daddr from sctp_addr. */ +/* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->daddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->daddr.s6_addr32[0] = 0; + inet6_sk(sk)->daddr.s6_addr32[1] = 0; + inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->daddr = addr->v6.sin6_addr; + } +} + +/* Initialize a sctp_addr from an address parameter. */ +static void sctp_v6_from_addr_param(union sctp_addr *addr, + union sctp_addr_param *param, + __u16 port, int iif) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = port; + addr->v6.sin6_flowinfo = 0; /* BUG */ + ipv6_addr_copy(&addr->v6.sin6_addr, ¶m->v6.addr); + addr->v6.sin6_scope_id = iif; +} + +/* Initialize an address parameter from a sctp_addr and return the length + * of the address parameter. + */ +static int sctp_v6_to_addr_param(const union sctp_addr *addr, + union sctp_addr_param *param) +{ + int length = sizeof(sctp_ipv6addr_param_t); + + param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS; + param->v6.param_hdr.length = ntohs(length); + ipv6_addr_copy(¶m->v6.addr, &addr->v6.sin6_addr); + + return length; } /* Initialize a sctp_addr from a dst_entry. */ @@ -396,13 +448,30 @@ } /* Compare addresses exactly. - * FIXME: v4-mapped-v6. + * v4-mapped-v6 is also in consideration. */ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2) { - if (addr1->sa.sa_family != addr2->sa.sa_family) + if (addr1->sa.sa_family != addr2->sa.sa_family) { + if (addr1->sa.sa_family == AF_INET && + addr2->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr2->v6.sin6_addr)) { + if (addr2->v6.sin6_port == addr1->v4.sin_port && + addr2->v6.sin6_addr.s6_addr32[3] == + addr1->v4.sin_addr.s_addr) + return 1; + } + if (addr2->sa.sa_family == AF_INET && + addr1->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr1->v6.sin6_addr)) { + if (addr1->v6.sin6_port == addr2->v4.sin_port && + addr1->v6.sin6_addr.s6_addr32[3] == + addr2->v4.sin_addr.s_addr) + return 1; + } return 0; + } if (ipv6_addr_cmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; /* If this is a linklocal address, compare the scope_id. */ @@ -433,7 +502,7 @@ } /* Should this be available for binding? */ -static int sctp_v6_available(const union sctp_addr *addr) +static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp) { int type; struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; @@ -441,6 +510,14 @@ type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) return 1; + if (type == IPV6_ADDR_MAPPED) { + if (sp && !sp->v4mapped) + return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->available(addr, sp); + } if (!(type & IPV6_ADDR_UNICAST)) return 0; @@ -454,11 +531,22 @@ * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v6_addr_valid(union sctp_addr *addr) +static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { int ret = ipv6_addr_type(&addr->v6.sin6_addr); - /* FIXME: v4-mapped-v6 address support. */ + /* Support v4-mapped-v6 address. */ + if (ret == IPV6_ADDR_MAPPED) { + /* Note: This routine is used in input, so v4-mapped-v6 + * are disallowed here when there is no sctp_opt. + */ + if (!sp || !sp->v4mapped) + return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); + } /* Is this a non-unicast address */ if (!(ret & IPV6_ADDR_UNICAST)) @@ -511,18 +599,18 @@ sock_init_data(NULL, newsk); sk_set_owner(newsk, THIS_MODULE); - newsk->type = SOCK_STREAM; + newsk->sk_type = SOCK_STREAM; - newsk->prot = sk->prot; - newsk->no_check = sk->no_check; - newsk->reuse = sk->reuse; - - newsk->destruct = inet_sock_destruct; - newsk->zapped = 0; - newsk->family = PF_INET6; - newsk->protocol = IPPROTO_SCTP; - newsk->backlog_rcv = sk->prot->backlog_rcv; - newsk->shutdown = sk->shutdown; + newsk->sk_prot = sk->sk_prot; + newsk->sk_no_check = sk->sk_no_check; + newsk->sk_reuse = sk->sk_reuse; + + newsk->sk_destruct = inet_sock_destruct; + newsk->sk_zapped = 0; + newsk->sk_family = PF_INET6; + newsk->sk_protocol = IPPROTO_SCTP; + newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; + newsk->sk_shutdown = sk->sk_shutdown; newinet = inet_sk(newsk); newnp = inet6_sk(newsk); @@ -533,17 +621,31 @@ * and getpeername(). */ newsk->sport = sk->sport; - newnp->saddr = np->saddr; + newsk->saddr = sk->saddr; newnp->rcv_saddr = np->rcv_saddr; newsk->dport = htons(asoc->peer.port); - newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr; + sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk); + + /* Init the ipv4 part of the socket since we can have sockets + * using v6 API for ipv4. + */ + newinet->ttl = sysctl_ip_default_ttl; + newinet->mc_loop = 1; + newinet->mc_ttl = 1; + newinet->mc_index = 0; + newinet->mc_list = NULL; + + if (ipv4_config.no_pmtu_disc) + newinet->pmtudisc = IP_PMTUDISC_DONT; + else + newinet->pmtudisc = IP_PMTUDISC_WANT; #ifdef INET_REFCNT_DEBUG atomic_inc(&inet6_sock_nr); atomic_inc(&inet_sock_nr); #endif - if (0 != newsk->prot->init(newsk)) { + if (newsk->sk_prot->init(newsk)) { inet_sock_release(newsk); newsk = NULL; } @@ -552,6 +654,13 @@ return newsk; } +/* Map v4 address to mapped v6 address */ +static void sctp_v6_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + if (sp->v4mapped && AF_INET == addr->sa.sa_family) + sctp_v4_map_v6(addr); +} + /* Where did this skb come from? */ static int sctp_v6_skb_iif(const struct sk_buff *skb) { @@ -559,6 +668,19 @@ return opt->iif; } +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v6_is_ce(const struct sk_buff *skb) +{ + return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20); +} + +/* Dump the v6 addr to the seq file. */ +static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) +{ + seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", + NIP6(&addr->v6.sin6_addr)); +} + /* Initialize a PF_INET6 socket msg_name. */ static void sctp_inet6_msgname(char *msgname, int *addr_len) { @@ -579,25 +701,28 @@ if (msgname) { union sctp_addr *addr; + struct sctp_association *asoc; + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet6_msgname(msgname, addrlen); sin6 = (struct sockaddr_in6 *)msgname; - sin6->sin6_port = htons(event->event_asoc->peer.port); - addr = &event->event_asoc->peer.primary_addr; + sin6->sin6_port = htons(asoc->peer.port); + addr = &asoc->peer.primary_addr; /* Note: If we go to a common v6 format, this code * will change. */ /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (AF_INET == addr->sa.sa_family) { - /* FIXME: Easy, but there was no way to test this - * yet. - */ + if (sctp_sk(asoc->base.sk)->v4mapped && + AF_INET == addr->sa.sa_family) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; return; } - sin6from = &event->event_asoc->peer.primary_addr.v6; + sin6from = &asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; @@ -617,16 +742,15 @@ sh = (struct sctphdr *)skb->h.raw; sin6->sin6_port = sh->source; - /* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */ - if (__constant_htons(ETH_P_IP) == skb->protocol) { - /* FIXME: The latest I-D added options for two - * behaviors. - */ + /* Map ipv4 address into v4-mapped-on-v6 address. */ + if (sctp_sk(skb->sk)->v4mapped && + skb->nh.iph->version == 4) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = skb->nh.iph->saddr; return; } /* Otherwise, just copy the v6 address. */ - ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { struct sctp_ulpevent *ev = sctp_skb2event(skb); @@ -636,16 +760,15 @@ } /* Do we support this AF? */ -static int sctp_inet6_af_supported(sa_family_t family) +static int sctp_inet6_af_supported(sa_family_t family, struct sctp_opt *sp) { - /* FIXME: v4-mapped-v6 addresses. The I-D is still waffling - * on what to do with sockaddr formats for PF_INET6 sockets. - * For now assume we'll support both. - */ switch (family) { case AF_INET6: - case AF_INET: return 1; + /* v4-mapped-v6 addresses */ + case AF_INET: + if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) + return 1; default: return 0; } @@ -689,7 +812,7 @@ else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = container_of(opt, struct sock, tp_pinfo.af_sctp); + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if @@ -697,13 +820,13 @@ */ if (addr->v6.sin6_scope_id) - sk->bound_dev_if = addr->v6.sin6_scope_id; - if (!sk->bound_dev_if) + sk->sk_bound_dev_if = addr->v6.sin6_scope_id; + if (!sk->sk_bound_dev_if) return 0; } af = opt->pf->af; } - return af->available(addr); + return af->available(addr, opt); } /* Verify that the provided sockaddr looks bindable. Common verification, @@ -719,7 +842,7 @@ else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = container_of(opt, struct sock, tp_pinfo.af_sctp); + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if @@ -727,8 +850,8 @@ */ if (addr->v6.sin6_scope_id) - sk->bound_dev_if = addr->v6.sin6_scope_id; - if (!sk->bound_dev_if) + sk->sk_bound_dev_if = addr->v6.sin6_scope_id; + if (!sk->sk_bound_dev_if) return 0; } af = opt->pf->af; @@ -810,6 +933,8 @@ .from_sk = sctp_v6_from_sk, .to_sk_saddr = sctp_v6_to_sk_saddr, .to_sk_daddr = sctp_v6_to_sk_daddr, + .from_addr_param = sctp_v6_from_addr_param, + .to_addr_param = sctp_v6_to_addr_param, .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, @@ -818,6 +943,8 @@ .is_any = sctp_v6_is_any, .available = sctp_v6_available, .skb_iif = sctp_v6_skb_iif, + .is_ce = sctp_v6_is_ce, + .seq_dump_addr = sctp_v6_seq_dump_addr, .net_header_len = sizeof(struct ipv6hdr), .sockaddr_len = sizeof(struct sockaddr_in6), .sa_family = AF_INET6, @@ -832,6 +959,7 @@ .send_verify = sctp_inet6_send_verify, .supported_addrs = sctp_inet6_supported_addrs, .create_accept_sk = sctp_v6_create_accept_sk, + .addr_v4map = sctp_v6_addr_v4map, .af = &sctp_ipv6_specific, }; diff -urN linux-2.4.25/net/sctp/objcnt.c linux-2.4.26/net/sctp/objcnt.c --- linux-2.4.25/net/sctp/objcnt.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/objcnt.c 2004-04-14 06:05:41.000000000 -0700 @@ -38,6 +38,7 @@ * be incorporated into the next SCTP release. */ +#include #include /* @@ -55,6 +56,7 @@ SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(ssnmap); +SCTP_DBG_OBJCNT(datamsg); /* An array to make it easy to pretty print the debug information * to the proc fs. @@ -68,6 +70,7 @@ SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(ssnmap), + SCTP_DBG_OBJCNT_ENTRY(datamsg), }; /* Callback from procfs to read out objcount information. @@ -86,7 +89,7 @@ char temp[128]; /* How many entries? */ - entries = sizeof(sctp_dbg_objcnt)/sizeof(sctp_dbg_objcnt[0]); + entries = ARRAY_SIZE(sctp_dbg_objcnt); /* Walk the entries and print out the debug information * for proc fs. diff -urN linux-2.4.25/net/sctp/output.c linux-2.4.26/net/sctp/output.c --- linux-2.4.25/net/sctp/output.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/output.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -97,6 +97,7 @@ packet->source_port = sport; packet->destination_port = dport; skb_queue_head_init(&packet->chunks); + packet->size = SCTP_IP_OVERHEAD; packet->vtag = 0; packet->ecn_capable = 0; packet->get_prepend_chunk = NULL; @@ -114,7 +115,7 @@ struct sctp_chunk *chunk; while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); if (packet->malloced) kfree(packet); @@ -138,7 +139,7 @@ if (!packet->has_cookie_echo) { error = sctp_packet_transmit(packet); if (error < 0) - chunk->skb->sk->err = -error; + chunk->skb->sk->sk_err = -error; /* If we have an empty packet, then we can NOT ever * return PMTU_FULL. @@ -219,22 +220,16 @@ /* Both control chunks and data chunks with TSNs are * non-fragmentable. */ - int fragmentable = sctp_chunk_is_data(chunk) && - (!chunk->has_tsn); - if (packet_empty) { - if (fragmentable) { - retval = SCTP_XMIT_MUST_FRAG; - goto finish; - } else { - /* The packet is too big but we can - * not fragment it--we have to just - * transmit and rely on IP - * fragmentation. - */ - packet->ipfragok = 1; - goto append; - } - } else { /* !packet_empty */ + if (packet_empty || !sctp_chunk_is_data(chunk)) { + /* We no longer do re-fragmentation. + * Just fragment at the IP layer, if we + * actually hit this condition + */ + + packet->ipfragok = 1; + goto append; + + } else { retval = SCTP_XMIT_PMTU_FULL; goto finish; } @@ -288,20 +283,18 @@ __u8 has_data = 0; struct dst_entry *dst; - /* Do NOT generate a chunkless packet... */ - if (skb_queue_empty(&packet->chunks)) + /* Do NOT generate a chunkless packet. */ + chunk = (struct sctp_chunk *)skb_peek(&packet->chunks); + if (unlikely(!chunk)) return err; /* Set up convenience variables... */ - chunk = (struct sctp_chunk *) (packet->chunks.next); sk = chunk->skb->sk; /* Allocate the new skb. */ nskb = dev_alloc_skb(packet->size); - if (!nskb) { - err = -ENOMEM; - goto out; - } + if (!nskb) + goto nomem; /* Make sure the outbound skb has enough header room reserved. */ skb_reserve(nskb, SCTP_IP_OVERHEAD); @@ -327,7 +320,6 @@ sh->vtag = htonl(packet->vtag); sh->checksum = 0; - /* 2) Calculate the Adler-32 checksum of the whole packet, * including the SCTP common header and all the * chunks. @@ -358,10 +350,11 @@ */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { - chunk->num_times_sent++; - chunk->sent_at = jiffies; if (sctp_chunk_is_data(chunk)) { - sctp_chunk_assign_tsn(chunk); + + if (!chunk->has_tsn) { + sctp_chunk_assign_ssn(chunk); + sctp_chunk_assign_tsn(chunk); /* 6.3.1 C4) When data is in flight and when allowed * by rule C5, a new RTT measurement MUST be made each @@ -369,23 +362,27 @@ * SHOULD be made no more than once per round-trip * for a given destination transport address. */ - if ((1 == chunk->num_times_sent) && - (!tp->rto_pending)) { - chunk->rtt_in_progress = 1; - tp->rto_pending = 1; - } + + if (!tp->rto_pending) { + chunk->rtt_in_progress = 1; + tp->rto_pending = 1; + } + } else + chunk->resent = 1; + + chunk->sent_at = jiffies; has_data = 1; } + padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len; if (padding) - memset(skb_put(chunk->skb, padding), 0, padding); + memset(skb_put(chunk->skb, padding), 0, padding); crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len), - chunk->skb->data, + chunk->skb->data, chunk->skb->len, crc32); - - SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, " - "%s %d\n", + + SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n", "*** Chunk", chunk, sctp_cname(SCTP_ST_CHUNK( chunk->chunk_hdr->type)), @@ -394,7 +391,6 @@ ntohl(chunk->subh.data_hdr->tsn) : 0, "length", ntohs(chunk->chunk_hdr->length), "chunk->skb->len", chunk->skb->len, - "num_times_sent", chunk->num_times_sent, "rtt_in_progress", chunk->rtt_in_progress); /* @@ -403,7 +399,7 @@ * acknowledged or have failed. */ if (!sctp_chunk_is_data(chunk)) - sctp_free_chunk(chunk); + sctp_chunk_free(chunk); } /* Perform final transformation on checksum. */ @@ -420,21 +416,17 @@ * data sender to indicate that the end-points of the * transport protocol are ECN-capable." * - * If ECN capable && negotiated && it makes sense for - * this packet to support it (e.g. post ECN negotiation) - * then lets set the ECT bit + * Now setting the ECT bit all the time, as it should not cause + * any problems protocol-wise even if our peer ignores it. * - * FIXME: Need to do something else for IPv6 + * Note: The works for IPv6 layer checks this bit too later + * in transmission. See IP6_ECN_flow_xmit(). */ - if (packet->ecn_capable) { - INET_ECN_xmit(nskb->sk); - } else { - INET_ECN_dontxmit(nskb->sk); - } + INET_ECN_xmit(nskb->sk); /* Set up the IP options. */ /* BUG: not implemented - * For v4 this all lives somewhere in sk->opt... + * For v4 this all lives somewhere in sk->sk_opt... */ /* Dump that on IP! */ @@ -452,8 +444,7 @@ tp->last_time_used = jiffies; /* Restart the AUTOCLOSE timer when sending data. */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (asoc->autoclose)) { + if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) { timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE]; @@ -474,9 +465,11 @@ if (!nskb->dst) goto no_route; - SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n", + SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n", nskb->len); + (*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); + out: packet->size = SCTP_IP_OVERHEAD; return err; @@ -492,7 +485,20 @@ * required. */ /* err = -EHOSTUNREACH; */ +err: + /* Control chunks are unreliable so just drop them. DATA chunks + * will get resent or dropped later. + */ + + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { + if (!sctp_chunk_is_data(chunk)) + sctp_chunk_free(chunk); + } goto out; +nomem: + err = -ENOMEM; + printk("%s alloc_skb failed.\n", __FUNCTION__); + goto err; } /******************************************************************** @@ -604,7 +610,7 @@ * unacknowledged. */ if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && - q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) { + q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) { unsigned len = datasize + q->out_qlen; /* Check whether this chunk and all the rest of pending @@ -630,6 +636,8 @@ rwnd = 0; asoc->peer.rwnd = rwnd; + /* Has been accepted for transmission. */ + chunk->msg->can_expire = 0; finish: return retval; diff -urN linux-2.4.25/net/sctp/outqueue.c linux-2.4.26/net/sctp/outqueue.c --- linux-2.4.25/net/sctp/outqueue.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sctp/outqueue.c 2004-04-14 06:05:41.000000000 -0700 @@ -56,13 +56,19 @@ #include /* Declare internal functions here. */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn); +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn); +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn, + int count_of_newacks); + /* Add data to the front of the queue. */ static inline void sctp_outq_head_data(struct sctp_outq *q, struct sctp_chunk *ch) @@ -100,6 +106,98 @@ q->out_qlen += ch->skb->len; } +/* + * SFR-CACC algorithm: + * D) If count_of_newacks is greater than or equal to 2 + * and t was not sent to the current primary then the + * sender MUST NOT increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks >=2 && transport != primary) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * F) If count_of_newacks is less than 2, let d be the + * destination to which t was sent. If cacc_saw_newack + * is 0 for destination d, then the sender MUST NOT + * increment missing report count for t. + */ +static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport, + int count_of_newacks) +{ + if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD + * execute steps C, D, F. + * + * C has been implemented in sctp_outq_sack + */ +static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks) +{ + if (!primary->cacc.cycling_changeover) { + if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks)) + return 1; + if (sctp_cacc_skip_3_1_f(transport, count_of_newacks)) + return 1; + return 0; + } + return 0; +} + +/* + * SFR-CACC algorithm: + * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less + * than next_tsn_at_change of the current primary, then + * the sender MUST NOT increment missing report count + * for t. + */ +static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) +{ + if (primary->cacc.cycling_changeover && + TSN_lt(tsn, primary->cacc.next_tsn_at_change)) + return 1; + return 0; +} + +/* + * SFR-CACC algorithm: + * 3) If the missing report count for TSN t is to be + * incremented according to [RFC2960] and + * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, + * then the sender MUST futher execute steps 3.1 and + * 3.2 to determine if the missing report count for + * TSN t SHOULD NOT be incremented. + * + * 3.3) If 3.1 and 3.2 do not dictate that the missing + * report count for t should not be incremented, then + * the sender SOULD increment missing report count for + * t (according to [RFC2960] and [SCTP_STEWART_2002]). + */ +static inline int sctp_cacc_skip(struct sctp_transport *primary, + struct sctp_transport *transport, + int count_of_newacks, + __u32 tsn) +{ + if (primary->cacc.changeover_active && + (sctp_cacc_skip_3_1(primary, transport, count_of_newacks) + || sctp_cacc_skip_3_2(primary, tsn))) + return 1; + return 0; +} + /* Generate a new outqueue. */ struct sctp_outq *sctp_outq_new(struct sctp_association *asoc) { @@ -133,6 +231,7 @@ q->outstanding_bytes = 0; q->empty = 1; + q->cork = 0; q->malloced = 0; q->out_qlen = 0; @@ -144,59 +243,51 @@ { struct sctp_transport *transport; struct list_head *lchunk, *pos, *temp; - sctp_chunk_t *chunk; - struct sctp_ulpevent *ev; + struct sctp_chunk *chunk; /* Throw away unacknowledged chunks. */ list_for_each(pos, &q->asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); while ((lchunk = sctp_list_dequeue(&transport->transmitted))) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); - - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_SENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as part of a failed message. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } } /* Throw away chunks that have been gap ACKed. */ list_for_each_safe(lchunk, temp, &q->sacked) { - list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + list_del_init(lchunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any chunks in the retransmit queue. */ list_for_each_safe(lchunk, temp, &q->retransmit) { - list_del(lchunk); - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - sctp_free_chunk(chunk); + list_del_init(lchunk); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } /* Throw away any leftover data chunks. */ while ((chunk = sctp_outq_dequeue_data(q))) { - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(q->asoc, - chunk, SCTP_DATA_UNSENT, - q->error, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&q->asoc->ulpq, ev); - - sctp_free_chunk(chunk); + /* Mark as send failure. */ + sctp_datamsg_fail(chunk, q->error); + sctp_chunk_free(chunk); } q->error = 0; /* Throw away any leftover control chunks. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control))) - sctp_free_chunk(chunk); + while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control))) + sctp_chunk_free(chunk); } /* Free the outqueue structure and any related pending chunks. */ @@ -211,7 +302,7 @@ } /* Put a new chunk in an sctp_outq. */ -int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) +int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) { int error = 0; @@ -266,7 +357,8 @@ if (error < 0) return error; - error = sctp_outq_flush(q, 0); + if (!q->cork) + error = sctp_outq_flush(q, 0); return error; } @@ -277,15 +369,16 @@ void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q) { struct list_head *rlchunk; - sctp_chunk_t *tchunk, *rchunk; + struct sctp_chunk *tchunk, *rchunk; __u32 ttsn, rtsn; int done = 0; - tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list); ttsn = ntohl(tchunk->subh.data_hdr->tsn); list_for_each(rlchunk, &q->retransmit) { - rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list); + rchunk = list_entry(rlchunk, struct sctp_chunk, + transmitted_list); rtsn = ntohl(rchunk->subh.data_hdr->tsn); if (TSN_lt(ttsn, rtsn)) { list_add(tlchunk, rlchunk->prev); @@ -304,11 +397,12 @@ __u8 fast_retransmit) { struct list_head *lchunk, *ltemp; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; /* Walk through the specified transmitted queue. */ list_for_each_safe(lchunk, ltemp, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* If we are doing retransmission due to a fast retransmit, * only the chunk's that are marked for fast retransmit @@ -352,7 +446,7 @@ /* Move the chunk to the retransmit queue. The chunks * on the retransmit queue is always kept in order. */ - list_del(lchunk); + list_del_init(lchunk); sctp_retransmit_insert(lchunk, q); } } @@ -399,7 +493,7 @@ error = sctp_outq_flush(q, /* rtx_timeout */ 1); if (error) - q->asoc->base.sk->err = -error; + q->asoc->base.sk->sk_err = -error; } /* @@ -417,7 +511,7 @@ struct list_head *lchunk; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sctp_association *asoc; int error = 0; @@ -443,7 +537,8 @@ lchunk = sctp_list_dequeue(lqueue); while (lchunk) { - chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + chunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the @@ -505,215 +600,19 @@ return error; } -/* This routine either transmits the fragment or puts it on the output - * queue. 'pos' points to the next chunk in the output queue after the - * chunk that is currently in the process of fragmentation. - */ -void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos, - struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn) -{ - struct sctp_transport *transport = packet->transport; - struct sk_buff_head *queue = &q->out; - sctp_xmit_t status; - int error; - - frag->subh.data_hdr->tsn = htonl(tsn); - frag->has_tsn = 1; - - /* An inner fragment may be smaller than the earlier one and may get - * in if we call q->build_output. This ensures that all the fragments - * are sent in order. - */ - if (!skb_queue_empty(queue)) { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - return; - } - - /* Add the chunk fragment to the packet. */ - status = (*q->build_output)(packet, frag); - switch (status) { - case SCTP_XMIT_RWND_FULL: - /* RWND is full, so put the chunk in the output queue. */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " - "adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - break; - - case SCTP_XMIT_OK: - error = (*q->force_output)(packet); - if (error < 0) { - /* Packet could not be transmitted, put the chunk in - * the output queue - */ - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "failed. adding 0x%x to outqueue\n", - ntohl(frag->subh.data_hdr->tsn)); - if (pos) - sctp_outq_insert_data(q, frag, pos); - else - sctp_outq_tail_data(q, frag); - } else { - SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " - "success. 0x%x sent\n", - ntohl(frag->subh.data_hdr->tsn)); - list_add_tail(&frag->transmitted_list, - &transport->transmitted); - - sctp_transport_reset_timers(transport); - } - break; - - default: - BUG(); - }; -} - -/* This routine calls sctp_xmit_frag() for all the fragments of a message. - * The argument 'frag' point to the first fragment and it holds the list - * of all the other fragments in the 'frag_list' field. - */ -void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt, - sctp_chunk_t *frag) -{ - struct sctp_association *asoc = frag->asoc; - struct list_head *lfrag, *frag_list; - __u32 tsn; - int nfrags = 1; - struct sctp_chunk *pos; - - /* Count the number of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - nfrags++; - } - - /* Get a TSN block of nfrags TSNs. */ - tsn = sctp_association_get_tsn_block(asoc, nfrags); - - pos = (struct sctp_chunk *)skb_peek(&q->out); - /* Transmit the first fragment. */ - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - - /* Transmit the rest of fragments. */ - frag_list = &frag->frag_list; - list_for_each(lfrag, frag_list) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_xmit_frag(q, pos, pkt, frag, tsn++); - } -} - -/* This routine breaks the given chunk into 'max_frag_data_len' size - * fragments. It returns the first fragment with the frag_list field holding - * the remaining fragments. - */ -sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, - size_t max_frag_data_len) +/* Cork the outqueue so queued chunks are really queued. */ +int sctp_outq_uncork(struct sctp_outq *q) { - struct sctp_association *asoc = chunk->asoc; - void *data_ptr = chunk->subh.data_hdr; - struct sctp_sndrcvinfo *sinfo = &chunk->sinfo; - __u16 chunk_data_len = sctp_data_size(chunk); - __u16 ssn = ntohs(chunk->subh.data_hdr->ssn); - sctp_chunk_t *first_frag, *frag; - struct list_head *frag_list; - int nfrags; - __u8 old_flags, flags; - - /* nfrags = no. of max size fragments + any smaller last fragment. */ - nfrags = ((chunk_data_len / max_frag_data_len) + - ((chunk_data_len % max_frag_data_len) ? 1 : 0)); - - /* Start of the data in the chunk. */ - data_ptr += sizeof(sctp_datahdr_t); - - /* Are we fragmenting an already fragmented large message? */ - old_flags = chunk->chunk_hdr->flags; - if (old_flags & SCTP_DATA_FIRST_FRAG) - flags = SCTP_DATA_FIRST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the first fragment. */ - first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, flags, ssn); - - if (!first_frag) - goto err; - first_frag->has_ssn = 1; - /* All the fragments are added to the frag_list of the first chunk. */ - frag_list = &first_frag->frag_list; - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - - /* Make the middle fragments. */ - while (chunk_data_len > max_frag_data_len) { - frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, - data_ptr, SCTP_DATA_MIDDLE_FRAG, - ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - /* Add the middle fragment to the first fragment's - * frag_list. - */ - list_add_tail(&frag->frag_list, frag_list); - - chunk_data_len -= max_frag_data_len; - data_ptr += max_frag_data_len; - } - - if (old_flags & SCTP_DATA_LAST_FRAG) - flags = SCTP_DATA_LAST_FRAG; - else - flags = SCTP_DATA_MIDDLE_FRAG; - - /* Make the last fragment. */ - frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr, - flags, ssn); - if (!frag) - goto err; - frag->has_ssn = 1; - - /* Add the last fragment to the first fragment's frag_list. */ - list_add_tail(&frag->frag_list, frag_list); - - /* Free the original chunk. */ - sctp_free_chunk(chunk); - - return first_frag; - -err: - /* Free any fragments that are created before the failure. */ - if (first_frag) { - struct list_head *flist, *lfrag; - - /* Free all the fragments off the first one. */ - flist = &first_frag->frag_list; - while (NULL != (lfrag = sctp_list_dequeue(flist))) { - frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_free_chunk(frag); - } - - /* Free the first fragment. */ - sctp_free_chunk(first_frag); + int error = 0; + if (q->cork) { + q->cork = 0; + error = sctp_outq_flush(q, 0); } - - return NULL; + return error; } /* - * sctp_outq_flush - Try to flush an outqueue. + * Try to flush an outqueue. * * Description: Send everything in q which we legally can, subject to * congestion limitations. @@ -736,7 +635,7 @@ struct sk_buff_head *queue; struct sctp_transport *transport = NULL; struct sctp_transport *new_transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; sctp_xmit_t status; int error = 0; int start_timer = 0; @@ -763,7 +662,7 @@ } queue = &q->control; - while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) { + while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) { /* Pick the right transport to use. */ new_transport = chunk->transport; @@ -903,32 +802,25 @@ */ if (chunk->sinfo.sinfo_stream >= asoc->c.sinit_num_ostreams) { - struct sctp_ulpevent *ev; - /* Generate a SEND FAILED event. */ - ev = sctp_ulpevent_make_send_failed(asoc, - chunk, SCTP_DATA_UNSENT, - SCTP_ERROR_INV_STRM, GFP_ATOMIC); - if (ev) - sctp_ulpq_tail_event(&asoc->ulpq, ev); - - /* Free the chunk. */ - sctp_free_chunk(chunk); + /* Mark as s failed send. */ + sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM); + sctp_chunk_free(chunk); continue; } - /* Now do delayed assignment of SSN. This will - * probably change again when we start supporting - * large (> approximately 2^16) size messages. - */ - sctp_chunk_assign_ssn(chunk); + /* Has this chunk expired? */ + if (sctp_datamsg_expires(chunk)) { + sctp_datamsg_fail(chunk, 0); + sctp_chunk_free(chunk); + continue; + } /* If there is a specified transport, use it. * Otherwise, we want to use the active path. */ new_transport = chunk->transport; - if (new_transport == NULL || - !new_transport->active) + if (!new_transport || !new_transport->active) new_transport = asoc->peer.active_path; /* Change packets if necessary. */ @@ -980,26 +872,6 @@ goto sctp_flush_out; break; - case SCTP_XMIT_MUST_FRAG: { - sctp_chunk_t *frag; - - frag = sctp_fragment_chunk(chunk, - packet->transport->asoc->frag_point); - if (!frag) { - /* We could not fragment due to out of - * memory condition. Free the original - * chunk and return ENOMEM. - */ - sctp_free_chunk(chunk); - error = -ENOMEM; - return error; - } - - sctp_xmit_fragmented_chunks(q, packet, frag); - goto sctp_flush_out; - break; - } - case SCTP_XMIT_OK: break; @@ -1079,7 +951,7 @@ /* Update unack_data based on the incoming SACK chunk */ static void sctp_sack_update_unack_data(struct sctp_association *assoc, - sctp_sackhdr_t *sack) + struct sctp_sackhdr *sack) { sctp_sack_variable_t *frags; __u16 unack_data; @@ -1097,12 +969,12 @@ } /* Return the highest new tsn that is acknowledged by the given SACK chunk. */ -static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack, +static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, struct sctp_association *asoc) { struct list_head *ltransport, *lchunk; struct sctp_transport *transport; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; __u32 highest_new_tsn, tsn; struct list_head *transport_list = &asoc->peer.transport_addr_list; @@ -1112,7 +984,7 @@ transport = list_entry(ltransport, struct sctp_transport, transports); list_for_each(lchunk, &transport->transmitted) { - chunk = list_entry(lchunk, sctp_chunk_t, + chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); tsn = ntohl(chunk->subh.data_hdr->tsn); @@ -1131,26 +1003,64 @@ * Process the SACK against the outqueue. Mostly, this just frees * things off the transmitted queue. */ -int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) +int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) { struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; - sctp_chunk_t *tchunk; - struct list_head *lchunk, *transport_list, *pos; + struct sctp_chunk *tchunk; + struct list_head *lchunk, *transport_list, *pos, *temp; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; __u32 highest_tsn, highest_new_tsn; __u32 sack_a_rwnd; - int outstanding; + unsigned outstanding; + struct sctp_transport *primary = asoc->peer.primary_path; + int count_of_newacks = 0; /* Grab the association's destination address list. */ transport_list = &asoc->peer.transport_addr_list; sack_ctsn = ntohl(sack->cum_tsn_ack); + /* + * SFR-CACC algorithm: + * On receipt of a SACK the sender SHOULD execute the + * following statements. + * + * 1) If the cumulative ack in the SACK passes next tsn_at_change + * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be + * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for + * all destinations. + */ + if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { + primary->cacc.changeover_active = 0; + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cycling_changeover = 0; + } + } + + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE + * is set the receiver of the SACK MUST take the following actions: + * + * A) Initialize the cacc_saw_newack to 0 for all destination + * addresses. + */ + if (sack->num_gap_ack_blocks > 0 && + primary->cacc.changeover_active) { + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + transport->cacc.cacc_saw_newack = 0; + } + } + /* Get the highest TSN in the sack. */ highest_tsn = sack_ctsn + - ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); + ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end); if (TSN_lt(asoc->highest_sacked, highest_tsn)) { highest_new_tsn = highest_tsn; @@ -1163,6 +1073,7 @@ * and free those chunks that we can. */ sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn); + sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0); /* Run through the transmitted queue. * Credit bytes received and free those chunks which we can. @@ -1174,6 +1085,20 @@ transports); sctp_check_transmitted(q, &transport->transmitted, transport, sack, highest_new_tsn); + /* + * SFR-CACC algorithm: + * C) Let count_of_newacks be the number of + * destinations for which cacc_saw_newack is set. + */ + if (transport->cacc.cacc_saw_newack) + count_of_newacks ++; + } + + list_for_each(pos, transport_list) { + transport = list_entry(pos, struct sctp_transport, + transports); + sctp_mark_missing(q, &transport->transmitted, transport, + highest_new_tsn, count_of_newacks); } /* Move the Cumulative TSN Ack Point if appropriate. */ @@ -1191,13 +1116,12 @@ "%p is 0x%x.\n", __FUNCTION__, asoc, ctsn); /* Throw away stuff rotting on the sack queue. */ - list_for_each(lchunk, &q->sacked) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + list_for_each_safe(lchunk, temp, &q->sacked) { + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); - if (TSN_lte(tsn, ctsn)) { - lchunk = lchunk->prev; - sctp_free_chunk(tchunk); - } + if (TSN_lte(tsn, ctsn)) + sctp_chunk_free(tchunk); } /* ii) Set rwnd equal to the newly received a_rwnd minus the @@ -1245,12 +1169,9 @@ * 2nd Level Abstractions ********************************************************************/ -/* Go through a transport's transmitted list or the assocication's retransmit +/* Go through a transport's transmitted list or the association's retransmit * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked. - * The retransmit list will not have an associated transport. In case of a - * transmitted list with a transport, the transport's congestion, rto and fast - * retransmit parameters are also updated and if needed a fast retransmit - * process is started. + * The retransmit list will not have an associated transport. * * I added coherent debug information output. --xguo * @@ -1261,17 +1182,16 @@ static void sctp_check_transmitted(struct sctp_outq *q, struct list_head *transmitted_queue, struct sctp_transport *transport, - sctp_sackhdr_t *sack, + struct sctp_sackhdr *sack, __u32 highest_new_tsn_in_sack) { struct list_head *lchunk; - sctp_chunk_t *tchunk; + struct sctp_chunk *tchunk; struct list_head tlist; __u32 tsn; __u32 sack_ctsn; __u32 rtt; __u8 restart_timer = 0; - __u8 do_fast_retransmit = 0; int bytes_acked = 0; /* These state variables are for coherent debug output. --xguo */ @@ -1295,7 +1215,8 @@ /* The while loop will skip empty transmitted queues. */ while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); + tchunk = list_entry(lchunk, struct sctp_chunk, + transmitted_list); tsn = ntohl(tchunk->subh.data_hdr->tsn); if (sctp_acked(sack, tsn)) { @@ -1316,9 +1237,9 @@ * first instance of the packet or a later * instance). */ - if ((!tchunk->tsn_gap_acked) && - (1 == tchunk->num_times_sent) && - (tchunk->rtt_in_progress)) { + if (!tchunk->tsn_gap_acked && + !tchunk->resent && + tchunk->rtt_in_progress) { rtt = jiffies - tchunk->sent_at; sctp_transport_update_rto(transport, rtt); @@ -1339,6 +1260,25 @@ if (!tchunk->tsn_gap_acked) { tchunk->tsn_gap_acked = 1; bytes_acked += sctp_data_size(tchunk); + /* + * SFR-CACC algorithm: + * 2) If the SACK contains gap acks + * and the flag CHANGEOVER_ACTIVE is + * set the receiver of the SACK MUST + * take the following action: + * + * B) For each TSN t being acked that + * has not been acked in any SACK so + * far, set cacc_saw_newack to 1 for + * the destination that the TSN was + * sent to. + */ + if (transport && + sack->num_gap_ack_blocks && + q->asoc->peer.primary_path->cacc. + changeover_active) + transport->cacc.cacc_saw_newack + = 1; } list_add_tail(&tchunk->transmitted_list, @@ -1525,8 +1465,8 @@ * receiver's advertised window is zero, and there is * only one data chunk in flight to the receiver. */ - if ((0 == q->asoc->peer.rwnd) && - (!list_empty(&tlist)) && + if (!q->asoc->peer.rwnd && + !list_empty(&tlist) && (sack_ctsn+2 == q->asoc->next_tsn)) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", @@ -1554,12 +1494,26 @@ } } - /* Reconstruct the transmitted list with chunks that are not yet - * acked by the Cumulative TSN Ack. - */ - while (NULL != (lchunk = sctp_list_dequeue(&tlist))) { - tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); - tsn = ntohl(tchunk->subh.data_hdr->tsn); + list_splice(&tlist, transmitted_queue); +} + +/* Mark chunks as missing and consequently may get retransmitted. */ +static void sctp_mark_missing(struct sctp_outq *q, + struct list_head *transmitted_queue, + struct sctp_transport *transport, + __u32 highest_new_tsn_in_sack, + int count_of_newacks) +{ + struct sctp_chunk *chunk; + struct list_head *pos; + __u32 tsn; + char do_fast_retransmit = 0; + struct sctp_transport *primary = q->asoc->peer.primary_path; + + list_for_each(pos, transmitted_queue) { + + chunk = list_entry(pos, struct sctp_chunk, transmitted_list); + tsn = ntohl(chunk->subh.data_hdr->tsn); /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all * 'Unacknowledged TSN's', if the TSN number of an @@ -1567,26 +1521,35 @@ * value, increment the 'TSN.Missing.Report' count on that * chunk if it has NOT been fast retransmitted or marked for * fast retransmit already. - * + */ + if (!chunk->fast_retransmit && + !chunk->tsn_gap_acked && + TSN_lt(tsn, highest_new_tsn_in_sack)) { + + /* SFR-CACC may require us to skip marking + * this chunk as missing. + */ + if (!transport || !sctp_cacc_skip(primary, transport, + count_of_newacks, tsn)) { + chunk->tsn_missing_report++; + + SCTP_DEBUG_PRINTK( + "%s: TSN 0x%x missing counter: %d\n", + __FUNCTION__, tsn, + chunk->tsn_missing_report); + } + } + /* * M4) If any DATA chunk is found to have a * 'TSN.Missing.Report' * value larger than or equal to 4, mark that chunk for * retransmission and start the fast retransmit procedure. */ - if ((!tchunk->fast_retransmit) && - (!tchunk->tsn_gap_acked) && - (TSN_lt(tsn, highest_new_tsn_in_sack))) { - tchunk->tsn_missing_report++; - SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n", - __FUNCTION__, tsn, - tchunk->tsn_missing_report); - } - if (tchunk->tsn_missing_report >= 4) { - tchunk->fast_retransmit = 1; + + if (chunk->tsn_missing_report >= 4) { + chunk->fast_retransmit = 1; do_fast_retransmit = 1; } - - list_add_tail(lchunk, transmitted_queue); } if (transport) { @@ -1602,7 +1565,7 @@ } /* Is the given TSN acked by this packet? */ -static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn) +static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn) { int i; sctp_sack_variable_t *frags; diff -urN linux-2.4.25/net/sctp/primitive.c linux-2.4.26/net/sctp/primitive.c --- linux-2.4.25/net/sctp/primitive.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/primitive.c 2004-04-14 06:05:41.000000000 -0700 @@ -39,6 +39,7 @@ * Narasimha Budihal * Karl Knutson * Ardelle Fan + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -203,3 +204,16 @@ */ DECLARE_PRIMITIVE(REQUESTHEARTBEAT); + +/* ADDIP +* 3.1.1 Address Configuration Change Chunk (ASCONF) +* +* This chunk is used to communicate to the remote endpoint one of the +* configuration change requests that MUST be acknowledged. The +* information carried in the ASCONF Chunk uses the form of a +* Type-Length-Value (TLV), as described in "3.2.1 Optional/ +* Variable-length Parameter Format" in RFC2960 [5], forall variable +* parameters. +*/ + +DECLARE_PRIMITIVE(ASCONF); diff -urN linux-2.4.25/net/sctp/proc.c linux-2.4.26/net/sctp/proc.c --- linux-2.4.25/net/sctp/proc.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/proc.c 2004-04-14 06:05:41.000000000 -0700 @@ -35,8 +35,6 @@ */ #include -#include -#include #include #include #include @@ -92,6 +90,7 @@ for (i = 0; i < sizeof(sctp_snmp_list) / sizeof(char *); i++) seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i], fold_field((void **)sctp_statistics, i)); + return 0; } @@ -102,6 +101,7 @@ } static struct file_operations sctp_snmp_seq_fops = { + .owner = THIS_MODULE, .open = sctp_snmp_seq_open, .read = seq_read, .llseek = seq_lseek, @@ -127,3 +127,162 @@ { remove_proc_entry("snmp", proc_net_sctp); } + +/* Dump local addresses of an association/endpoint. */ +static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) +{ + struct list_head *pos; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *addr; + struct sctp_af *af; + + list_for_each(pos, &epb->bind_addr.address_list) { + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); + addr = (union sctp_addr *)&laddr->a; + af = sctp_get_af_specific(addr->sa.sa_family); + af->seq_dump_addr(seq, addr); + } +} + +/* Dump remote addresses of an association. */ +static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc) +{ + struct list_head *pos; + struct sctp_transport *transport; + union sctp_addr *addr; + struct sctp_af *af; + + list_for_each(pos, &assoc->peer.transport_addr_list) { + transport = list_entry(pos, struct sctp_transport, transports); + addr = (union sctp_addr *)&transport->ipaddr; + af = sctp_get_af_specific(addr->sa.sa_family); + af->seq_dump_addr(seq, addr); + } +} + +/* Display sctp endpoints (/proc/net/sctp/eps). */ +static int sctp_eps_seq_show(struct seq_file *seq, void *v) +{ + struct sctp_hashbucket *head; + struct sctp_ep_common *epb; + struct sctp_endpoint *ep; + struct sock *sk; + int hash; + + seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT LADDRS\n"); + for (hash = 0; hash < sctp_ep_hashsize; hash++) { + head = &sctp_ep_hashtable[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + ep = sctp_ep(epb); + sk = epb->sk; + seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk, + sctp_sk(sk)->type, sk->sk_state, hash, + epb->bind_addr.port); + sctp_seq_dump_local_addrs(seq, epb); + seq_printf(seq, "\n"); + } + read_unlock(&head->lock); + } + + return 0; +} + +/* Initialize the seq file operations for 'eps' object. */ +static int sctp_eps_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, sctp_eps_seq_show, NULL); +} + +static struct file_operations sctp_eps_seq_fops = { + .open = sctp_eps_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* Set up the proc fs entry for 'eps' object. */ +int __init sctp_eps_proc_init(void) +{ + struct proc_dir_entry *p; + + p = create_proc_entry("eps", S_IRUGO, proc_net_sctp); + if (!p) + return -ENOMEM; + + p->proc_fops = &sctp_eps_seq_fops; + + return 0; +} + +/* Cleanup the proc fs entry for 'eps' object. */ +void sctp_eps_proc_exit(void) +{ + remove_proc_entry("eps", proc_net_sctp); +} + +/* Display sctp associations (/proc/net/sctp/assocs). */ +static int sctp_assocs_seq_show(struct seq_file *seq, void *v) +{ + struct sctp_hashbucket *head; + struct sctp_ep_common *epb; + struct sctp_association *assoc; + struct sock *sk; + int hash; + + seq_printf(seq, " ASSOC SOCK STY SST ST HBKT LPORT RPORT " + "LADDRS <-> RADDRS\n"); + for (hash = 0; hash < sctp_assoc_hashsize; hash++) { + head = &sctp_assoc_hashtable[hash]; + read_lock(&head->lock); + for (epb = head->chain; epb; epb = epb->next) { + assoc = sctp_assoc(epb); + sk = epb->sk; + seq_printf(seq, + "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ", + assoc, sk, sctp_sk(sk)->type, sk->sk_state, + assoc->state, hash, epb->bind_addr.port, + assoc->peer.port); + sctp_seq_dump_local_addrs(seq, epb); + seq_printf(seq, "<-> "); + sctp_seq_dump_remote_addrs(seq, assoc); + seq_printf(seq, "\n"); + } + read_unlock(&head->lock); + } + + return 0; +} + +/* Initialize the seq file operations for 'assocs' object. */ +static int sctp_assocs_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, sctp_assocs_seq_show, NULL); +} + +static struct file_operations sctp_assocs_seq_fops = { + .open = sctp_assocs_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* Set up the proc fs entry for 'assocs' object. */ +int __init sctp_assocs_proc_init(void) +{ + struct proc_dir_entry *p; + + p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp); + if (!p) + return -ENOMEM; + + p->proc_fops = &sctp_assocs_seq_fops; + + return 0; +} + +/* Cleanup the proc fs entry for 'assocs' object. */ +void sctp_assocs_proc_exit(void) +{ + remove_proc_entry("assocs", proc_net_sctp); +} diff -urN linux-2.4.25/net/sctp/protocol.c linux-2.4.26/net/sctp/protocol.c --- linux-2.4.25/net/sctp/protocol.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/protocol.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll @@ -50,15 +50,17 @@ #include #include #include +#include #include #include #include #include #include #include +#include /* Global data structures. */ -struct sctp_protocol sctp_proto; +struct sctp_globals sctp_globals; struct proc_dir_entry *proc_net_sctp; DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics); @@ -73,10 +75,16 @@ static struct sctp_af *sctp_af_v4_specific; static struct sctp_af *sctp_af_v6_specific; +kmem_cache_t *sctp_chunk_cachep; + extern struct net_proto_family inet_family_ops; extern int sctp_snmp_proc_init(void); extern int sctp_snmp_proc_exit(void); +extern int sctp_eps_proc_init(void); +extern int sctp_eps_proc_exit(void); +extern int sctp_assocs_proc_init(void); +extern int sctp_assocs_proc_exit(void); /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) @@ -87,8 +95,6 @@ /* Set up the proc fs entry for the SCTP protocol. */ __init int sctp_proc_init(void) { - int rc = 0; - if (!proc_net_sctp) { struct proc_dir_entry *ent; ent = proc_mkdir("net/sctp", 0); @@ -96,20 +102,31 @@ ent->owner = THIS_MODULE; proc_net_sctp = ent; } else - rc = -ENOMEM; + goto out_nomem; } if (sctp_snmp_proc_init()) - rc = -ENOMEM; + goto out_nomem; + if (sctp_eps_proc_init()) + goto out_nomem; + if (sctp_assocs_proc_init()) + goto out_nomem; + + return 0; - return rc; +out_nomem: + return -ENOMEM; } -/* Clean up the proc fs entry for the SCTP protocol. */ +/* Clean up the proc fs entry for the SCTP protocol. + * Note: Do not make this __exit as it is used in the init error + * path. + */ void sctp_proc_exit(void) { - sctp_snmp_proc_exit(); + sctp_eps_proc_exit(); + sctp_assocs_proc_exit(); if (proc_net_sctp) { proc_net_sctp = NULL; @@ -125,7 +142,7 @@ { struct in_device *in_dev; struct in_ifaddr *ifa; - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; read_lock(&inetdev_lock); if ((in_dev = __in_dev_get(dev)) == NULL) { @@ -136,7 +153,7 @@ read_lock(&in_dev->lock); for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { /* Add the address to the local list. */ - addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC); + addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_port = 0; @@ -152,7 +169,7 @@ /* Extract our IP addresses from the system and stash them in the * protocol structure. */ -static void __sctp_get_local_addr_list(struct sctp_protocol *proto) +static void __sctp_get_local_addr_list(void) { struct net_device *dev; struct list_head *pos; @@ -160,59 +177,58 @@ read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { - list_for_each(pos, &proto->address_families) { + list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); - af->copy_addrlist(&proto->local_addr_list, dev); + af->copy_addrlist(&sctp_local_addr_list, dev); } } read_unlock(&dev_base_lock); } -static void sctp_get_local_addr_list(struct sctp_protocol *proto) +static void sctp_get_local_addr_list(void) { unsigned long flags; - sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); - __sctp_get_local_addr_list(&sctp_proto); - sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + __sctp_get_local_addr_list(); + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); } /* Free the existing local addresses. */ -static void __sctp_free_local_addr_list(struct sctp_protocol *proto) +static void __sctp_free_local_addr_list(void) { - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; struct list_head *pos, *temp; - list_for_each_safe(pos, temp, &proto->local_addr_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + list_for_each_safe(pos, temp, &sctp_local_addr_list) { + addr = list_entry(pos, struct sctp_sockaddr_entry, list); list_del(pos); kfree(addr); } } /* Free the existing local addresses. */ -static void sctp_free_local_addr_list(struct sctp_protocol *proto) +static void sctp_free_local_addr_list(void) { unsigned long flags; - sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); - __sctp_free_local_addr_list(proto); - sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + __sctp_free_local_addr_list(); + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); } /* Copy the local addresses which are valid for 'scope' into 'bp'. */ -int sctp_copy_local_addr_list(struct sctp_protocol *proto, - struct sctp_bind_addr *bp, sctp_scope_t scope, +int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, int gfp, int copy_flags) { - struct sockaddr_storage_list *addr; + struct sctp_sockaddr_entry *addr; int error = 0; struct list_head *pos; unsigned long flags; - sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); - list_for_each(pos, &proto->local_addr_list) { - addr = list_entry(pos, struct sockaddr_storage_list, list); + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + list_for_each(pos, &sctp_local_addr_list) { + addr = list_entry(pos, struct sctp_sockaddr_entry, list); if (sctp_in_scope(&addr->a, scope)) { /* Now that the address is in scope, check to see if * the address type is really supported by the local @@ -232,7 +248,7 @@ } end_copy: - sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); return error; } @@ -262,20 +278,45 @@ static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk) { addr->v4.sin_family = AF_INET; - addr->v4.sin_port = (sk)->num; - addr->v4.sin_addr.s_addr = (sk)->rcv_saddr; + addr->v4.sin_port = sk->num; + addr->v4.sin_addr.s_addr = sk->rcv_saddr; } -/* Initialize sk->rcv_saddr from sctp_addr. */ +/* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - (sk)->rcv_saddr = addr->v4.sin_addr.s_addr; + sk->rcv_saddr = addr->v4.sin_addr.s_addr; } -/* Initialize sk->daddr from sctp_addr. */ +/* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - (sk)->daddr = addr->v4.sin_addr.s_addr; + sk->daddr = addr->v4.sin_addr.s_addr; +} + +/* Initialize a sctp_addr from an address parameter. */ +static void sctp_v4_from_addr_param(union sctp_addr *addr, + union sctp_addr_param *param, + __u16 port, int iif) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = port; + addr->v4.sin_addr.s_addr = param->v4.addr.s_addr; +} + +/* Initialize an address parameter from a sctp_addr and return the length + * of the address parameter. + */ +static int sctp_v4_to_addr_param(const union sctp_addr *addr, + union sctp_addr_param *param) +{ + int length = sizeof(sctp_ipv4addr_param_t); + + param->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS; + param->v4.param_hdr.length = ntohs(length); + param->v4.addr.s_addr = addr->v4.sin_addr.s_addr; + + return length; } /* Initialize a sctp_addr from a dst_entry. */ @@ -323,7 +364,7 @@ * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v4_addr_valid(union sctp_addr *addr) +static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) @@ -333,7 +374,7 @@ } /* Should this be available for binding? */ -static int sctp_v4_available(const union sctp_addr *addr) +static int sctp_v4_available(union sctp_addr *addr, struct sctp_opt *sp) { int ret = inet_addr_type(addr->v4.sin_addr.s_addr); @@ -393,16 +434,20 @@ { struct rtable *rt; struct rt_key key; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; rwlock_t *addr_lock; - struct sockaddr_storage_list *laddr; + struct sctp_sockaddr_entry *laddr; struct list_head *pos; struct dst_entry *dst = NULL; union sctp_addr dst_saddr; - + memset(&key, 0x0, sizeof(struct rt_key)); key.dst = daddr->v4.sin_addr.s_addr; - + + if (asoc) { + key.tos = RT_CONN_FLAGS(asoc->base.sk); + key.oif = asoc->base.sk->bound_dev_if; + } if (saddr) key.src = saddr->v4.sin_addr.s_addr; @@ -429,7 +474,7 @@ */ sctp_read_lock(addr_lock); list_for_each(pos, &bp->address_list) { - laddr = list_entry(pos, struct sockaddr_storage_list, + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); sctp_v4_dst_saddr(&dst_saddr, dst, bp->port); if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) @@ -449,7 +494,7 @@ */ sctp_read_lock(addr_lock); list_for_each(pos, &bp->address_list) { - laddr = list_entry(pos, struct sockaddr_storage_list, list); + laddr = list_entry(pos, struct sctp_sockaddr_entry, list); if (AF_INET == laddr->a.sa.sa_family) { key.src = laddr->a.v4.sin_addr.s_addr; @@ -490,11 +535,17 @@ } /* What interface did this skb arrive on? */ -int sctp_v4_skb_iif(const struct sk_buff *skb) +static int sctp_v4_skb_iif(const struct sk_buff *skb) { return ((struct rtable *)skb->dst)->rt_iif; } +/* Was this packet marked by Explicit Congestion Notification? */ +static int sctp_v4_is_ce(const struct sk_buff *skb) +{ + return INET_ECN_is_ce(skb->nh.iph->tos); +} + /* Create and initialize a new sk for the socket returned by accept(). */ struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sctp_association *asoc) @@ -510,18 +561,18 @@ sock_init_data(NULL, newsk); sk_set_owner(newsk, THIS_MODULE); - newsk->type = SOCK_STREAM; + newsk->sk_type = SOCK_STREAM; - newsk->prot = sk->prot; - newsk->no_check = sk->no_check; - newsk->reuse = sk->reuse; - newsk->shutdown = sk->shutdown; - - newsk->destruct = inet_sock_destruct; - newsk->zapped = 0; - newsk->family = PF_INET; - newsk->protocol = IPPROTO_SCTP; - newsk->backlog_rcv = sk->prot->backlog_rcv; + newsk->sk_prot = sk->sk_prot; + newsk->sk_no_check = sk->sk_no_check; + newsk->sk_reuse = sk->sk_reuse; + newsk->sk_shutdown = sk->sk_shutdown; + + newsk->sk_destruct = inet_sock_destruct; + newsk->sk_zapped = 0; + newsk->sk_family = PF_INET; + newsk->sk_protocol = IPPROTO_SCTP; + newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; newinet = inet_sk(newsk); @@ -546,7 +597,7 @@ atomic_inc(&inet_sock_nr); #endif - if (0 != newsk->prot->init(newsk)) { + if (newsk->sk_prot->init(newsk)) { inet_sock_release(newsk); newsk = NULL; } @@ -555,6 +606,18 @@ return newsk; } +/* Map address, empty for v4 family */ +static void sctp_v4_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + /* Empty */ +} + +/* Dump the v4 addr to the seq file. */ +static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) +{ + seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr)); +} + /* Event handler for inet address addition/deletion events. * Basically, whenever there is an event, we re-build our local address list. */ @@ -563,10 +626,10 @@ { unsigned long flags; - sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); - __sctp_free_local_addr_list(&sctp_proto); - __sctp_get_local_addr_list(&sctp_proto); - sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); + sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); + __sctp_free_local_addr_list(); + __sctp_get_local_addr_list(); + sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); return NOTIFY_DONE; } @@ -592,7 +655,7 @@ "SCTP: Failed to create the SCTP control socket.\n"); return err; } - sctp_ctl_socket->sk->allocation = GFP_ATOMIC; + sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL; return 0; @@ -617,7 +680,7 @@ } INIT_LIST_HEAD(&af->list); - list_add_tail(&af->list, &sctp_proto.address_families); + list_add_tail(&af->list, &sctp_address_families); return 1; } @@ -654,10 +717,13 @@ struct sockaddr_in *sin, *sinfrom; if (msgname) { + struct sctp_association *asoc; + + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet_msgname(msgname, addr_len); sin = (struct sockaddr_in *)msgname; - sinfrom = &event->event_asoc->peer.primary_addr.v4; - sin->sin_port = htons(event->event_asoc->peer.port); + sinfrom = &asoc->peer.primary_addr.v4; + sin->sin_port = htons(asoc->peer.port); sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; } } @@ -678,7 +744,7 @@ } /* Do we support this AF? */ -static int sctp_inet_af_supported(sa_family_t family) +static int sctp_inet_af_supported(sa_family_t family, struct sctp_opt *sp) { /* PF_INET only supports AF_INET addresses. */ return (AF_INET == family); @@ -706,7 +772,7 @@ */ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) { - return sctp_v4_available(addr); + return sctp_v4_available(addr, opt); } /* Verify that sockaddr looks sendable. Common verification has already @@ -752,6 +818,7 @@ .send_verify = sctp_inet_send_verify, .supported_addrs = sctp_inet_supported_addrs, .create_accept_sk = sctp_v4_create_accept_sk, + .addr_v4map = sctp_v4_addr_v4map, .af = &sctp_ipv4_specific, }; @@ -821,6 +888,8 @@ .from_sk = sctp_v4_from_sk, .to_sk_saddr = sctp_v4_to_sk_saddr, .to_sk_daddr = sctp_v4_to_sk_daddr, + .from_addr_param= sctp_v4_from_addr_param, + .to_addr_param = sctp_v4_to_addr_param, .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, @@ -829,6 +898,8 @@ .available = sctp_v4_available, .scope = sctp_v4_scope, .skb_iif = sctp_v4_skb_iif, + .is_ce = sctp_v4_is_ce, + .seq_dump_addr = sctp_v4_seq_dump_addr, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), .sa_family = AF_INET, @@ -873,6 +944,7 @@ static void cleanup_sctp_mibs(void) { + return; } /* Initialize the universe into something sensible. */ @@ -880,6 +952,8 @@ { int i; int status = 0; + unsigned long goal; + int order; /* SCTP_DEBUG sanity check. */ if (!sctp_sanity_check()) @@ -892,6 +966,14 @@ inet_register_protosw(&sctp_seqpacket_protosw); inet_register_protosw(&sctp_stream_protosw); + /* Allocate cache pools. */ + sctp_chunk_cachep = kmem_cache_create("sctp_chunk", + sizeof(struct sctp_chunk), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (!sctp_chunk_cachep) + goto err_chunk_cachep; + /* Allocate and initialise sctp mibs. */ status = init_sctp_mibs(); if (status) @@ -910,91 +992,116 @@ */ /* The following protocol parameters are RECOMMENDED: */ /* RTO.Initial - 3 seconds */ - sctp_proto.rto_initial = SCTP_RTO_INITIAL; + sctp_rto_initial = SCTP_RTO_INITIAL; /* RTO.Min - 1 second */ - sctp_proto.rto_min = SCTP_RTO_MIN; + sctp_rto_min = SCTP_RTO_MIN; /* RTO.Max - 60 seconds */ - sctp_proto.rto_max = SCTP_RTO_MAX; + sctp_rto_max = SCTP_RTO_MAX; /* RTO.Alpha - 1/8 */ - sctp_proto.rto_alpha = SCTP_RTO_ALPHA; + sctp_rto_alpha = SCTP_RTO_ALPHA; /* RTO.Beta - 1/4 */ - sctp_proto.rto_beta = SCTP_RTO_BETA; - + sctp_rto_beta = SCTP_RTO_BETA; /* Valid.Cookie.Life - 60 seconds */ - sctp_proto.valid_cookie_life = 60 * HZ; + sctp_valid_cookie_life = 60 * HZ; /* Whether Cookie Preservative is enabled(1) or not(0) */ - sctp_proto.cookie_preserve_enable = 1; + sctp_cookie_preserve_enable = 1; /* Max.Burst - 4 */ - sctp_proto.max_burst = SCTP_MAX_BURST; + sctp_max_burst = SCTP_MAX_BURST; /* Association.Max.Retrans - 10 attempts * Path.Max.Retrans - 5 attempts (per destination address) * Max.Init.Retransmits - 8 attempts */ - sctp_proto.max_retrans_association = 10; - sctp_proto.max_retrans_path = 5; - sctp_proto.max_retrans_init = 8; + sctp_max_retrans_association = 10; + sctp_max_retrans_path = 5; + sctp_max_retrans_init = 8; /* HB.interval - 30 seconds */ - sctp_proto.hb_interval = 30 * HZ; + sctp_hb_interval = 30 * HZ; /* Implementation specific variables. */ /* Initialize default stream count setup information. */ - sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS; - sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS; + sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; + sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; - /* Allocate and initialize the association hash table. */ - sctp_proto.assoc_hashsize = 4096; - sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) - kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); - if (!sctp_proto.assoc_hashbucket) { + /* Size and allocate the association hash table. + * The methodology is similar to that of the tcp hash tables. + */ + if (num_physpages >= (128 * 1024)) + goal = num_physpages >> (22 - PAGE_SHIFT); + else + goal = num_physpages >> (24 - PAGE_SHIFT); + + for (order = 0; (1UL << order) < goal; order++) + ; + + do { + sctp_assoc_hashsize = (1UL << order) * PAGE_SIZE / + sizeof(struct sctp_hashbucket); + if ((sctp_assoc_hashsize > (64 * 1024)) && order > 0) + continue; + sctp_assoc_hashtable = (struct sctp_hashbucket *) + __get_free_pages(GFP_ATOMIC, order); + } while (!sctp_assoc_hashtable && --order > 0); + if (!sctp_assoc_hashtable) { printk(KERN_ERR "SCTP: Failed association hash alloc.\n"); status = -ENOMEM; goto err_ahash_alloc; } - for (i = 0; i < sctp_proto.assoc_hashsize; i++) { - sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED; - sctp_proto.assoc_hashbucket[i].chain = NULL; + for (i = 0; i < sctp_assoc_hashsize; i++) { + sctp_assoc_hashtable[i].lock = RW_LOCK_UNLOCKED; + sctp_assoc_hashtable[i].chain = NULL; } /* Allocate and initialize the endpoint hash table. */ - sctp_proto.ep_hashsize = 64; - sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) - kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); - if (!sctp_proto.ep_hashbucket) { + sctp_ep_hashsize = 64; + sctp_ep_hashtable = (struct sctp_hashbucket *) + kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL); + if (!sctp_ep_hashtable) { printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); status = -ENOMEM; goto err_ehash_alloc; } - - for (i = 0; i < sctp_proto.ep_hashsize; i++) { - sctp_proto.ep_hashbucket[i].lock = RW_LOCK_UNLOCKED; - sctp_proto.ep_hashbucket[i].chain = NULL; + for (i = 0; i < sctp_ep_hashsize; i++) { + sctp_ep_hashtable[i].lock = RW_LOCK_UNLOCKED; + sctp_ep_hashtable[i].chain = NULL; } /* Allocate and initialize the SCTP port hash table. */ - sctp_proto.port_hashsize = 4096; - sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) - kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); - if (!sctp_proto.port_hashtable) { + do { + sctp_port_hashsize = (1UL << order) * PAGE_SIZE / + sizeof(struct sctp_bind_hashbucket); + if ((sctp_port_hashsize > (64 * 1024)) && order > 0) + continue; + sctp_port_hashtable = (struct sctp_bind_hashbucket *) + __get_free_pages(GFP_ATOMIC, order); + } while (!sctp_port_hashtable && --order > 0); + if (!sctp_port_hashtable) { printk(KERN_ERR "SCTP: Failed bind hash alloc."); status = -ENOMEM; goto err_bhash_alloc; } - - sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED; - sctp_proto.port_rover = sysctl_local_port_range[0] - 1; - for (i = 0; i < sctp_proto.port_hashsize; i++) { - sctp_proto.port_hashtable[i].lock = SPIN_LOCK_UNLOCKED; - sctp_proto.port_hashtable[i].chain = NULL; + for (i = 0; i < sctp_port_hashsize; i++) { + sctp_port_hashtable[i].lock = SPIN_LOCK_UNLOCKED; + sctp_port_hashtable[i].chain = NULL; } + sctp_port_alloc_lock = SPIN_LOCK_UNLOCKED; + sctp_port_rover = sysctl_local_port_range[0] - 1; + + printk(KERN_INFO "SCTP: Hash tables configured " + "(established %d bind %d)\n", + sctp_assoc_hashsize, sctp_port_hashsize); + + /* Disable ADDIP by default. */ + sctp_addip_enable = 0; + sctp_sysctl_register(); - INIT_LIST_HEAD(&sctp_proto.address_families); + INIT_LIST_HEAD(&sctp_address_families); sctp_register_af(&sctp_ipv4_specific); status = sctp_v6_init(); @@ -1009,13 +1116,13 @@ } /* Initialize the local address list. */ - INIT_LIST_HEAD(&sctp_proto.local_addr_list); - sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&sctp_local_addr_list); + sctp_local_addr_lock = SPIN_LOCK_UNLOCKED; /* Register notifier for inet address additions/deletions. */ register_inetaddr_notifier(&sctp_inetaddr_notifier); - sctp_get_local_addr_list(&sctp_proto); + sctp_get_local_addr_list(); __unsafe(THIS_MODULE); return 0; @@ -1025,16 +1132,22 @@ err_v6_init: sctp_sysctl_unregister(); list_del(&sctp_ipv4_specific.list); - kfree(sctp_proto.port_hashtable); + free_pages((unsigned long)sctp_port_hashtable, + get_order(sctp_port_hashsize * + sizeof(struct sctp_bind_hashbucket))); err_bhash_alloc: - kfree(sctp_proto.ep_hashbucket); + kfree(sctp_ep_hashtable); err_ehash_alloc: - kfree(sctp_proto.assoc_hashbucket); + free_pages((unsigned long)sctp_assoc_hashtable, + get_order(sctp_assoc_hashsize * + sizeof(struct sctp_hashbucket))); err_ahash_alloc: sctp_dbg_objcnt_exit(); sctp_proc_exit(); cleanup_sctp_mibs(); err_init_mibs: + kmem_cache_destroy(sctp_chunk_cachep); +err_chunk_cachep: inet_del_protocol(&sctp_protocol); inet_unregister_protosw(&sctp_seqpacket_protosw); inet_unregister_protosw(&sctp_stream_protosw); @@ -1052,7 +1165,7 @@ unregister_inetaddr_notifier(&sctp_inetaddr_notifier); /* Free the local address list. */ - sctp_free_local_addr_list(&sctp_proto); + sctp_free_local_addr_list(); /* Free the control endpoint. */ sock_release(sctp_ctl_socket); @@ -1061,9 +1174,15 @@ sctp_sysctl_unregister(); list_del(&sctp_ipv4_specific.list); - kfree(sctp_proto.assoc_hashbucket); - kfree(sctp_proto.ep_hashbucket); - kfree(sctp_proto.port_hashtable); + free_pages((unsigned long)sctp_assoc_hashtable, + get_order(sctp_assoc_hashsize * + sizeof(struct sctp_hashbucket))); + kfree(sctp_ep_hashtable); + free_pages((unsigned long)sctp_port_hashtable, + get_order(sctp_port_hashsize * + sizeof(struct sctp_bind_hashbucket))); + + kmem_cache_destroy(sctp_chunk_cachep); sctp_dbg_objcnt_exit(); sctp_proc_exit(); diff -urN linux-2.4.25/net/sctp/sm_make_chunk.c linux-2.4.26/net/sctp/sm_make_chunk.c --- linux-2.4.25/net/sctp/sm_make_chunk.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/sm_make_chunk.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,8 +1,8 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2002 Intel Corp. - * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -48,6 +48,7 @@ * Sridhar Samudrala * Daisy Chang * Ardelle Fan + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -60,6 +61,7 @@ #include #include #include +#include #include #include @@ -67,6 +69,8 @@ #include #include +extern kmem_cache_t *sctp_chunk_cachep; + /* What was the inbound interface for this chunk? */ int sctp_chunk_iif(const struct sctp_chunk *chunk) { @@ -96,7 +100,7 @@ * provided chunk, as most cause codes will be embedded inside an * abort chunk. */ -void sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code, +void sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { sctp_errhdr_t err; @@ -157,14 +161,14 @@ * Host Name Address (Note 3) Optional 11 * Supported Address Types (Note 4) Optional 12 */ -sctp_chunk_t *sctp_make_init(const struct sctp_association *asoc, - const sctp_bind_addr_t *bp, +struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, + const struct sctp_bind_addr *bp, int gfp, int vparam_len) { sctp_inithdr_t init; union sctp_params addrs; size_t chunksize; - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; int num_types, addrs_len = 0; struct sctp_opt *sp; sctp_supported_addrs_param_t sat; @@ -234,12 +238,12 @@ return retval; } -sctp_chunk_t *sctp_make_init_ack(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, int gfp, int unkparam_len) { sctp_inithdr_t initack; - sctp_chunk_t *retval; + struct sctp_chunk *retval; union sctp_params addrs; int addrs_len; sctp_cookie_param_t *cookie; @@ -347,10 +351,10 @@ * An implementation SHOULD make the cookie as small as possible * to insure interoperability. */ -sctp_chunk_t *sctp_make_cookie_echo(const struct sctp_association *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *cookie; int cookie_len; @@ -398,10 +402,10 @@ * * Set to zero on transmit and ignored on receipt. */ -sctp_chunk_t *sctp_make_cookie_ack(const struct sctp_association *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0); @@ -443,11 +447,11 @@ * * Note: The CWR is considered a Control chunk. */ -sctp_chunk_t *sctp_make_cwr(const struct sctp_association *asoc, +struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc, const __u32 lowest_tsn, - const sctp_chunk_t *chunk) + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_cwrhdr_t cwr; cwr.lowest_tsn = htonl(lowest_tsn); @@ -478,10 +482,10 @@ } /* Make an ECNE chunk. This is a congestion experienced report. */ -sctp_chunk_t *sctp_make_ecne(const struct sctp_association *asoc, +struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc, const __u32 lowest_tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_ecnehdr_t ecne; ecne.lowest_tsn = htonl(lowest_tsn); @@ -499,25 +503,27 @@ /* Make a DATA chunk for the given association from the provided * parameters. However, do not populate the data payload. */ -sctp_chunk_t *sctp_make_datafrag_empty(struct sctp_association *asoc, +struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; - sctp_datahdr_t dp; + struct sctp_chunk *retval; + struct sctp_datahdr dp; int chunk_len; /* We assign the TSN as LATE as possible, not here when * creating the chunk. */ - dp.tsn= 1000000; /* This marker is a debugging aid. */ + dp.tsn = 0; dp.stream = htons(sinfo->sinfo_stream); - dp.ppid = htonl(sinfo->sinfo_ppid); - dp.ssn = htons(ssn); + dp.ppid = sinfo->sinfo_ppid; /* Set the flags for an unordered send. */ - if (sinfo->sinfo_flags & MSG_UNORDERED) + if (sinfo->sinfo_flags & MSG_UNORDERED) { flags |= SCTP_DATA_UNORDERED; + dp.ssn = 0; + } else + dp.ssn = htons(ssn); chunk_len = sizeof(dp) + data_len; retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len); @@ -534,12 +540,12 @@ /* Make a DATA chunk for the given association. Populate the data * payload. */ -sctp_chunk_t *sctp_make_datafrag(struct sctp_association *asoc, +struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data, __u8 flags, __u16 ssn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn); if (retval) @@ -551,11 +557,11 @@ /* Make a DATA chunk for the given association to ride on stream id * 'stream', with a payload id of 'payload', and a body of 'data'. */ -sctp_chunk_t *sctp_make_data(struct sctp_association *asoc, +struct sctp_chunk *sctp_make_data(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len, const __u8 *data) { - sctp_chunk_t *retval = NULL; + struct sctp_chunk *retval = NULL; retval = sctp_make_data_empty(asoc, sinfo, data_len); if (retval) @@ -568,7 +574,7 @@ * hold 'data_len' octets of data. We use this version when we need * to build the message AFTER allocating memory. */ -sctp_chunk_t *sctp_make_data_empty(struct sctp_association *asoc, +struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc, const struct sctp_sndrcvinfo *sinfo, int data_len) { @@ -581,30 +587,20 @@ * association. This reports on which TSN's we've seen to date, * including duplicates and gaps. */ -sctp_chunk_t *sctp_make_sack(const struct sctp_association *asoc) +struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc) { - sctp_chunk_t *retval; - sctp_sackhdr_t sack; - sctp_gap_ack_block_t gab; - int length; + struct sctp_chunk *retval; + struct sctp_sackhdr sack; + int len; __u32 ctsn; - struct sctp_tsnmap_iter iter; __u16 num_gabs, num_dup_tsns; struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map; ctsn = sctp_tsnmap_get_ctsn(map); - SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn); - - /* Count the number of Gap Ack Blocks. */ - num_gabs = 0; - - if (sctp_tsnmap_has_gap(map)) { - sctp_tsnmap_iter_init(map, &iter); - while (sctp_tsnmap_next_gap_ack(map, &iter, - &gab.start, &gab.end)) - num_gabs++; - } + SCTP_DEBUG_PRINTK("sackCTSNAck sent: 0x%x.\n", ctsn); + /* How much room is needed in the chunk? */ + num_gabs = sctp_tsnmap_num_gabs(map); num_dup_tsns = sctp_tsnmap_num_dups(map); /* Initialize the SACK header. */ @@ -613,12 +609,12 @@ sack.num_gap_ack_blocks = htons(num_gabs); sack.num_dup_tsns = htons(num_dup_tsns); - length = sizeof(sack) - + sizeof(sctp_gap_ack_block_t) * num_gabs + len = sizeof(sack) + + sizeof(struct sctp_gap_ack_block) * num_gabs + sizeof(__u32) * num_dup_tsns; /* Create the chunk. */ - retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length); + retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, len); if (!retval) goto nodata; @@ -657,30 +653,25 @@ retval->subh.sack_hdr = sctp_addto_chunk(retval, sizeof(sack), &sack); - /* Put the Gap Ack Blocks into the chunk. */ - if (num_gabs) { - sctp_tsnmap_iter_init(map, &iter); - while(sctp_tsnmap_next_gap_ack(map, &iter, - &gab.start, &gab.end)) { - gab.start = htons(gab.start); - gab.end = htons(gab.end); - sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), - &gab); - } - } - - /* Register the duplicates. */ - sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, - sctp_tsnmap_get_dups(map)); + /* Add the gap ack block information. */ + if (num_gabs) + sctp_addto_chunk(retval, sizeof(__u32) * num_gabs, + sctp_tsnmap_get_gabs(map)); + + /* Add the duplicate TSN information. */ + if (num_dup_tsns) + sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns, + sctp_tsnmap_get_dups(map)); nodata: return retval; } /* Make a SHUTDOWN chunk. */ -sctp_chunk_t *sctp_make_shutdown(const struct sctp_association *asoc) +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_shutdownhdr_t shut; __u32 ctsn; @@ -694,14 +685,17 @@ retval->subh.shutdown_hdr = sctp_addto_chunk(retval, sizeof(shut), &shut); + + if (chunk) + retval->transport = chunk->transport; nodata: return retval; } -sctp_chunk_t *sctp_make_shutdown_ack(const struct sctp_association *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0); @@ -720,10 +714,11 @@ return retval; } -sctp_chunk_t *sctp_make_shutdown_complete(const struct sctp_association *asoc, - const sctp_chunk_t *chunk) +struct sctp_chunk *sctp_make_shutdown_complete( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -750,11 +745,11 @@ /* Create an ABORT. Note that we set the T bit if we have no * association. */ -sctp_chunk_t *sctp_make_abort(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const size_t hint) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u8 flags = 0; /* Maybe set the T-bit if we have no association. */ @@ -778,10 +773,11 @@ } /* Helper to create ABORT with a NO_USER_DATA error. */ -sctp_chunk_t *sctp_make_abort_no_data(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, __u32 tsn) +struct sctp_chunk *sctp_make_abort_no_data( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u32 tsn) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; __u32 payload; retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) @@ -812,17 +808,22 @@ } /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error. */ -sctp_chunk_t *sctp_make_abort_user(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const struct msghdr *msg) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; void *payload = NULL, *payoff; - size_t paylen; - struct iovec *iov = msg->msg_iov; - int iovlen = msg->msg_iovlen; + size_t paylen = 0; + struct iovec *iov = NULL; + int iovlen = 0; + + if (msg) { + iov = msg->msg_iov; + iovlen = msg->msg_iovlen; + paylen = get_user_iov_size(iov, iovlen); + } - paylen = get_user_iov_size(iov, iovlen); retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen); if (!retval) goto err_chunk; @@ -852,19 +853,19 @@ err_copy: kfree(payload); err_payload: - sctp_free_chunk(retval); + sctp_chunk_free(retval); retval = NULL; err_chunk: return retval; } /* Make a HEARTBEAT chunk. */ -sctp_chunk_t *sctp_make_heartbeat(const struct sctp_association *asoc, +struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, const struct sctp_transport *transport, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, - 0, paylen); + struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, + 0, paylen); if (!retval) goto nodata; @@ -879,15 +880,16 @@ return retval; } -sctp_chunk_t *sctp_make_heartbeat_ack(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, const void *payload, const size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, - 0, paylen); + struct sctp_chunk *retval; + retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen); if (!retval) goto nodata; + retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload); /* RFC 2960 6.4 Multi-homed SCTP Endpoints @@ -909,11 +911,12 @@ /* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ -sctp_chunk_t *sctp_make_op_error_space(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, - size_t size) +struct sctp_chunk *sctp_make_op_error_space( + const struct sctp_association *asoc, + const struct sctp_chunk *chunk, + size_t size) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, sizeof(sctp_errhdr_t) + size); @@ -936,13 +939,14 @@ } /* Create an Operation Error chunk. */ -sctp_chunk_t *sctp_make_op_error(const struct sctp_association *asoc, - const sctp_chunk_t *chunk, +struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc, + const struct sctp_chunk *chunk, __u16 cause_code, const void *payload, size_t paylen) { - sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen); + struct sctp_chunk *retval; + retval = sctp_make_op_error_space(asoc, chunk, paylen); if (!retval) goto nodata; @@ -959,15 +963,17 @@ /* Turn an skb into a chunk. * FIXME: Eventually move the structure directly inside the skb->cb[]. */ -sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, +struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, const struct sctp_association *asoc, struct sock *sk) { - sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC); + struct sctp_chunk *retval; + + retval = kmem_cache_alloc(sctp_chunk_cachep, SLAB_ATOMIC); if (!retval) goto nodata; - memset(retval, 0, sizeof(sctp_chunk_t)); + memset(retval, 0, sizeof(struct sctp_chunk)); if (!sk) { SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb); @@ -975,11 +981,11 @@ retval->skb = skb; retval->asoc = (struct sctp_association *)asoc; - retval->num_times_sent = 0; + retval->resent = 0; retval->has_tsn = 0; retval->has_ssn = 0; retval->rtt_in_progress = 0; - retval->sent_at = jiffies; + retval->sent_at = 0; retval->singleton = 1; retval->end_of_packet = 0; retval->ecn_ce_done = 0; @@ -995,17 +1001,24 @@ retval->tsn_gap_acked = 0; retval->fast_retransmit = 0; + /* If this is a fragmented message, track all fragments + * of the message (for SEND_FAILED). + */ + retval->msg = NULL; + /* Polish the bead hole. */ INIT_LIST_HEAD(&retval->transmitted_list); INIT_LIST_HEAD(&retval->frag_list); SCTP_DBG_OBJCNT_INC(chunk); + atomic_set(&retval->refcnt, 1); + nodata: return retval; } /* Set chunk->source and dest based on the IP header in chunk->skb. */ -void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src, +void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src, union sctp_addr *dest) { memcpy(&chunk->source, src, sizeof(union sctp_addr)); @@ -1013,7 +1026,7 @@ } /* Extract the source address from a chunk. */ -const union sctp_addr *sctp_source(const sctp_chunk_t *chunk) +const union sctp_addr *sctp_source(const struct sctp_chunk *chunk) { /* If we have a known transport, use that. */ if (chunk->transport) { @@ -1027,10 +1040,10 @@ /* Create a new chunk, setting the type and flags headers from the * arguments, reserving enough space for a 'paylen' byte payload. */ -sctp_chunk_t *sctp_make_chunk(const struct sctp_association *asoc, - __u8 type, __u8 flags, int paylen) +struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, + __u8 type, __u8 flags, int paylen) { - sctp_chunk_t *retval; + struct sctp_chunk *retval; sctp_chunkhdr_t *chunk_hdr; struct sk_buff *skb; struct sock *sk; @@ -1055,36 +1068,58 @@ } retval->chunk_hdr = chunk_hdr; - retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(sctp_chunkhdr_t); + retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr); /* Set the skb to the belonging sock for accounting. */ skb->sk = sk; return retval; - nodata: return NULL; } + /* Release the memory occupied by a chunk. */ -void sctp_free_chunk(sctp_chunk_t *chunk) +static void sctp_chunk_destroy(struct sctp_chunk *chunk) { - /* Make sure that we are not on any list. */ - skb_unlink((struct sk_buff *) chunk); - list_del(&chunk->transmitted_list); - /* Free the chunk skb data and the SCTP_chunk stub itself. */ dev_kfree_skb(chunk->skb); - kfree(chunk); SCTP_DBG_OBJCNT_DEC(chunk); + kmem_cache_free(sctp_chunk_cachep, chunk); +} + +/* Possibly, free the chunk. */ +void sctp_chunk_free(struct sctp_chunk *chunk) +{ + /* Make sure that we are not on any list. */ + skb_unlink((struct sk_buff *) chunk); + list_del_init(&chunk->transmitted_list); + + /* Release our reference on the message tracker. */ + if (chunk->msg) + sctp_datamsg_put(chunk->msg); + + sctp_chunk_put(chunk); +} + +/* Grab a reference to the chunk. */ +void sctp_chunk_hold(struct sctp_chunk *ch) +{ + atomic_inc(&ch->refcnt); } +/* Release a reference to the chunk. */ +void sctp_chunk_put(struct sctp_chunk *ch) +{ + if (atomic_dec_and_test(&ch->refcnt)) + sctp_chunk_destroy(ch); +} /* Append bytes to the end of a chunk. Will panic if chunk is not big * enough. */ -void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data) +void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data) { void *target; void *padding; @@ -1108,8 +1143,8 @@ * chunk is not big enough. * Returns a kernel err value. */ -static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len, - struct iovec *data) +int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len, + struct iovec *data) { __u8 *target; int err = 0; @@ -1130,132 +1165,10 @@ return err; } -/* A data chunk can have a maximum payload of (2^16 - 20). Break - * down any such message into smaller chunks. Opportunistically, fragment - * the chunks down to the current MTU constraints. We may get refragmented - * later if the PMTU changes, but it is _much better_ to fragment immediately - * with a reasonable guess than always doing our fragmentation on the - * soft-interrupt. - */ - - -int sctp_datachunks_from_user(struct sctp_association *asoc, - const struct sctp_sndrcvinfo *sinfo, - struct msghdr *msg, int msg_len, - struct sk_buff_head *chunks) -{ - int max, whole, i, offset, over, err; - int len, first_len; - sctp_chunk_t *chunk; - __u8 frag; - - /* What is a reasonable fragmentation point right now? */ - max = asoc->pmtu; - if (max < SCTP_MIN_PMTU) - max = SCTP_MIN_PMTU; - max -= SCTP_IP_OVERHEAD; - - /* Make sure not beyond maximum chunk size. */ - if (max > SCTP_MAX_CHUNK_LEN) - max = SCTP_MAX_CHUNK_LEN; - - /* Subtract out the overhead of a data chunk header. */ - max -= sizeof(struct sctp_data_chunk); - - whole = 0; - first_len = max; - - /* Encourage Cookie-ECHO bundling. */ - if (asoc->state < SCTP_STATE_COOKIE_ECHOED) { - whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN); - - /* Account for the DATA to be bundled with the COOKIE-ECHO. */ - if (whole) { - first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN; - msg_len -= first_len; - whole = 1; - } - } - - /* How many full sized? How many bytes leftover? */ - whole += msg_len / max; - over = msg_len % max; - offset = 0; - - if (whole && over) - SCTP_INC_STATS_USER(SctpFragUsrMsgs); - - /* Create chunks for all the full sized DATA chunks. */ - for (i=0, len=first_len; i < whole; i++) { - frag = SCTP_DATA_MIDDLE_FRAG; - - if (0 == i) - frag |= SCTP_DATA_FIRST_FRAG; - - if ((i == (whole - 1)) && !over) - frag |= SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0); - - if (!chunk) - goto nomem; - err = sctp_user_addto_chunk(chunk, offset, len, msg->msg_iov); - if (err < 0) - goto errout; - - offset += len; - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - - /* The first chunk, the first chunk was likely short - * to allow bundling, so reset to full size. - */ - if (0 == i) - len = max; - } - - /* .. now the leftover bytes. */ - if (over) { - if (!whole) - frag = SCTP_DATA_NOT_FRAG; - else - frag = SCTP_DATA_LAST_FRAG; - - chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0); - - if (!chunk) - goto nomem; - - err = sctp_user_addto_chunk(chunk, offset, over, msg->msg_iov); - - /* Put the chunk->skb back into the form expected by send. */ - __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr - - (__u8 *)chunk->skb->data); - if (err < 0) - goto errout; - - __skb_queue_tail(chunks, (struct sk_buff *)chunk); - } - err = 0; - goto out; - -nomem: - err = -ENOMEM; -errout: - while ((chunk = (sctp_chunk_t *)__skb_dequeue(chunks))) - sctp_free_chunk(chunk); -out: - return err; -} - /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_ssn(sctp_chunk_t *chunk) +void sctp_chunk_assign_ssn(struct sctp_chunk *chunk) { __u16 ssn; __u16 sid; @@ -1282,7 +1195,7 @@ /* Helper function to assign a TSN if needed. This assumes that both * the data_hdr and association have already been assigned. */ -void sctp_chunk_assign_tsn(sctp_chunk_t *chunk) +void sctp_chunk_assign_tsn(struct sctp_chunk *chunk) { if (!chunk->has_tsn) { /* This is the last possible instant to @@ -1301,6 +1214,7 @@ struct sctp_association *asoc; struct sk_buff *skb; sctp_scope_t scope; + struct sctp_af *af; /* Create the bare association. */ scope = sctp_scope(sctp_source(chunk)); @@ -1310,29 +1224,10 @@ asoc->temp = 1; skb = chunk->skb; /* Create an entry for the source address of the packet. */ - /* FIXME: Use the af specific helpers. */ - switch (skb->nh.iph->version) { - case 4: - asoc->c.peer_addr.v4.sin_family = AF_INET; - asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source); - asoc->c.peer_addr.v4.sin_addr.s_addr = skb->nh.iph->saddr; - break; - - case 6: - asoc->c.peer_addr.v6.sin6_family = AF_INET6; - asoc->c.peer_addr.v6.sin6_port - = ntohs(chunk->sctp_hdr->source); - asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */ - asoc->c.peer_addr.v6.sin6_addr = skb->nh.ipv6h->saddr; - asoc->c.peer_addr.v6.sin6_scope_id = - ((struct inet6_skb_parm *)skb->cb)->iif; - break; - - default: - /* Yikes! I never heard of this kind of address. */ + af = sctp_get_af_specific(ipver2af(skb->nh.iph->version)); + if (unlikely(!af)) goto fail; - }; - + af->from_skb(&asoc->c.peer_addr, skb, 1); nodata: return asoc; @@ -1346,19 +1241,19 @@ */ sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - const sctp_chunk_t *init_chunk, + const struct sctp_chunk *init_chunk, int *cookie_len, const __u8 *raw_addrs, int addrs_len) { sctp_cookie_param_t *retval; - sctp_signed_cookie_t *cookie; + struct sctp_signed_cookie *cookie; struct scatterlist sg; int headersize, bodysize; unsigned int keylen; char *key; headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE; - bodysize = sizeof(sctp_cookie_t) + bodysize = sizeof(struct sctp_cookie) + ntohs(init_chunk->chunk_hdr->length) + addrs_len; /* Pad out the cookie to a multiple to make the signature @@ -1380,7 +1275,7 @@ * out on the network. */ memset(retval, 0x00, *cookie_len); - cookie = (sctp_signed_cookie_t *) retval->body; + cookie = (struct sctp_signed_cookie *) retval->body; /* Set up the parameter header. */ retval->p.type = SCTP_PARAM_STATE_COOKIE; @@ -1388,22 +1283,21 @@ /* Copy the cookie part of the association itself. */ cookie->c = asoc->c; - /* Save the raw address list length in the cookie. */ cookie->c.raw_addr_list_len = addrs_len; /* Set an expiration time for the cookie. */ do_gettimeofday(&cookie->c.expiration); - tv_add(&asoc->cookie_life, &cookie->c.expiration); + TIMEVAL_ADD(asoc->cookie_life, cookie->c.expiration); /* Copy the peer's init packet. */ memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr, ntohs(init_chunk->chunk_hdr->length)); /* Copy the raw local address list of the association. */ - memcpy((__u8 *)&cookie->c.peer_init[0] + + memcpy((__u8 *)&cookie->c.peer_init[0] + ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len); - + if (sctp_sk(ep->base.sk)->hmac) { /* Sign the message. */ sg.page = virt_to_page(&cookie->c); @@ -1411,13 +1305,10 @@ sg.length = bodysize; keylen = SCTP_SECRET_SIZE; key = (char *)ep->secret_key[ep->current_key]; - - sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, cookie->signature); - } else - sctp_hash_digest(ep->secret_key[ep->current_key], - SCTP_SECRET_SIZE, (__u8 *) &cookie->c, - bodysize, cookie->signature); + } nodata: return retval; @@ -1427,31 +1318,30 @@ struct sctp_association *sctp_unpack_cookie( const struct sctp_endpoint *ep, const struct sctp_association *asoc, - sctp_chunk_t *chunk, int gfp, - int *error, sctp_chunk_t **errp) + struct sctp_chunk *chunk, int gfp, + int *error, struct sctp_chunk **errp) { struct sctp_association *retval = NULL; - sctp_signed_cookie_t *cookie; - sctp_cookie_t *bear_cookie; + struct sctp_signed_cookie *cookie; + struct sctp_cookie *bear_cookie; int headersize, bodysize, fixed_size; __u8 digest[SCTP_SIGNATURE_SIZE]; - int secret; struct scatterlist sg; - unsigned int keylen; + unsigned int keylen, len; char *key; sctp_scope_t scope; struct sk_buff *skb = chunk->skb; headersize = sizeof(sctp_chunkhdr_t) + SCTP_SECRET_SIZE; bodysize = ntohs(chunk->chunk_hdr->length) - headersize; - fixed_size = headersize + sizeof(sctp_cookie_t); + fixed_size = headersize + sizeof(struct sctp_cookie); /* Verify that the chunk looks like it even has a cookie. * There must be enough room for our cookie and our peer's * INIT chunk. */ - if (ntohs(chunk->chunk_hdr->length) < - (fixed_size + sizeof(sctp_chunkhdr_t))) + len = ntohs(chunk->chunk_hdr->length); + if (len < fixed_size + sizeof(struct sctp_chunkhdr)) goto malformed; /* Verify that the cookie has been padded out. */ @@ -1462,28 +1352,8 @@ cookie = chunk->subh.cookie_hdr; bear_cookie = &cookie->c; - if (!sctp_sk(ep->base.sk)->hmac) { - secret = ep->current_key; - sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE, - (__u8 *) bear_cookie, bodysize, digest); - - if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { - /* Try the previous key. */ - secret = ep->last_key; - sctp_hash_digest(ep->secret_key[secret], - SCTP_SECRET_SIZE, (__u8 *) bear_cookie, - bodysize, digest); - - if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { - /* Yikes! Still bad signature! */ - *error = -SCTP_IERROR_BAD_SIG; - goto fail; - } - - } - + if (!sctp_sk(ep->base.sk)->hmac) goto no_hmac; - } /* Check the signature. */ keylen = SCTP_SECRET_SIZE; @@ -1493,16 +1363,16 @@ key = (char *)ep->secret_key[ep->current_key]; memset(digest, 0x00, sizeof(digest)); - sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { - /* Try the previous key. */ + /* Try the previous key. */ key = (char *)ep->secret_key[ep->last_key]; memset(digest, 0x00, sizeof(digest)); - sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, + sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg, 1, digest); - + if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) { /* Yikes! Still bad signature! */ *error = -SCTP_IERROR_BAD_SIG; @@ -1555,7 +1425,7 @@ retval->peer.port = ntohs(chunk->sctp_hdr->source); /* Populate the association from the cookie. */ - retval->c = *bear_cookie; + memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie)); if (sctp_assoc_set_bind_addr_from_cookie(retval, bear_cookie, GFP_ATOMIC) < 0) { @@ -1565,12 +1435,13 @@ /* Also, add the destination address. */ if (list_empty(&retval->base.bind_addr.address_list)) { - sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, + sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, GFP_ATOMIC); } retval->next_tsn = retval->c.initial_tsn; retval->ctsn_ack_point = retval->next_tsn - 1; + retval->addip_serial = retval->c.initial_tsn; /* The INIT stuff will be done by the side effects. */ return retval; @@ -1603,8 +1474,8 @@ */ static int sctp_process_missing_param(const struct sctp_association *asoc, sctp_param_t paramtype, - sctp_chunk_t *chunk, - sctp_chunk_t **errp) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { struct __sctp_missing report; __u16 len; @@ -1630,8 +1501,8 @@ /* Report an Invalid Mandatory Parameter. */ static int sctp_process_inv_mandatory(const struct sctp_association *asoc, - sctp_chunk_t *chunk, - sctp_chunk_t **errp) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { /* Invalid Mandatory Parameter Error has no payload. */ @@ -1650,8 +1521,8 @@ */ static int sctp_process_hn_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **errp) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { __u16 len = ntohs(param.p->length); @@ -1695,8 +1566,8 @@ */ static int sctp_process_unk_param(const struct sctp_association *asoc, union sctp_params param, - sctp_chunk_t *chunk, - sctp_chunk_t **errp) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { int retval = 1; @@ -1758,8 +1629,8 @@ static int sctp_verify_param(const struct sctp_association *asoc, union sctp_params param, sctp_cid_t cid, - sctp_chunk_t *chunk, - sctp_chunk_t **err_chunk) + struct sctp_chunk *chunk, + struct sctp_chunk **err_chunk) { int retval = 1; @@ -1796,8 +1667,8 @@ int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t cid, sctp_init_chunk_t *peer_init, - sctp_chunk_t *chunk, - sctp_chunk_t **errp) + struct sctp_chunk *chunk, + struct sctp_chunk **errp) { union sctp_params param; int has_cookie = 0; @@ -1831,8 +1702,12 @@ sctp_walk_params(param, peer_init, init_hdr.params) { - if (!sctp_verify_param(asoc, param, cid, chunk, errp)) - return 0; + if (!sctp_verify_param(asoc, param, cid, chunk, errp)) { + if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type) + return 0; + else + return 1; + } } /* for (loop through all parameters) */ @@ -1939,11 +1814,14 @@ * stream sequence number shall be set to 0. */ - /* Allocate storage for the negotiated streams. */ - asoc->ssnmap = sctp_ssnmap_new(asoc->peer.i.num_outbound_streams, - asoc->c.sinit_num_ostreams, gfp); - if (!asoc->ssnmap) - goto nomem_ssnmap; + /* Allocate storage for the negotiated streams if it is not a temporary * association. + */ + if (!asoc->temp) { + asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams, + asoc->c.sinit_num_ostreams, gfp); + if (!asoc->ssnmap) + goto nomem_ssnmap; + } /* ADDIP Section 4.1 ASCONF Chunk Procedures * @@ -1963,7 +1841,7 @@ /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { transport = list_entry(pos, struct sctp_transport, transports); - list_del(pos); + list_del_init(pos); sctp_transport_free(transport); } nomem: @@ -1991,6 +1869,7 @@ int retval = 1; sctp_scope_t scope; time_t stale; + struct sctp_af *af; /* We maintain all INIT parameters in network byte order all the * time. This allows us to not worry about whether the parameters @@ -1998,11 +1877,12 @@ */ switch (param.p->type) { case SCTP_PARAM_IPV6_ADDRESS: - if( PF_INET6 != asoc->base.sk->family) + if (PF_INET6 != asoc->base.sk->sk_family) break; /* Fall through. */ case SCTP_PARAM_IPV4_ADDRESS: - sctp_param2sockaddr(&addr, param.addr, asoc->peer.port, 0); + af = sctp_get_af_specific(param_type2af(param.p->type)); + af->from_addr_param(&addr, param.addr, asoc->peer.port, 0); scope = sctp_scope(peer_addr); if (sctp_in_scope(&addr, scope)) if (!sctp_assoc_add_peer(asoc, &addr, gfp)) @@ -2010,7 +1890,7 @@ break; case SCTP_PARAM_COOKIE_PRESERVATIVE: - if (!sctp_proto.cookie_preserve_enable) + if (!sctp_cookie_preserve_enable) break; stale = ntohl(param.life->lifespan_increment); @@ -2114,86 +1994,619 @@ return retval; } -/******************************************************************** - * 4th Level Abstractions - ********************************************************************/ - -/* Convert from an SCTP IP parameter to a union sctp_addr. */ -void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *param, - __u16 port, int iif) +/* + * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0xC1 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Serial Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Parameter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF Parameter #1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / .... / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF Parameter #N | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Address Parameter and other parameter will not be wrapped in this function + */ +struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, + union sctp_addr *addr, int vparam_len) { - switch(param->v4.param_hdr.type) { - case SCTP_PARAM_IPV4_ADDRESS: - addr->v4.sin_family = AF_INET; - addr->v4.sin_port = port; - addr->v4.sin_addr.s_addr = param->v4.addr.s_addr; - break; + sctp_addiphdr_t asconf; + struct sctp_chunk *retval; + int length = sizeof(asconf) + vparam_len; + union sctp_addr_param addrparam; + int addrlen; + struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); + + addrlen = af->to_addr_param(addr, &addrparam); + if (!addrlen) + return NULL; + length += addrlen; - case SCTP_PARAM_IPV6_ADDRESS: - addr->v6.sin6_family = AF_INET6; - addr->v6.sin6_port = port; - addr->v6.sin6_flowinfo = 0; /* BUG */ - addr->v6.sin6_addr = param->v6.addr; - addr->v6.sin6_scope_id = iif; - break; + /* Create the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length); + if (!retval) + return NULL; - default: - SCTP_DEBUG_PRINTK("Illegal address type %d\n", - ntohs(param->v4.param_hdr.type)); - break; - }; + asconf.serial = htonl(asoc->addip_serial++); + + retval->subh.addip_hdr = + sctp_addto_chunk(retval, sizeof(asconf), &asconf); + retval->param_hdr.v = + sctp_addto_chunk(retval, addrlen, &addrparam); + + return retval; +} + +/* ADDIP + * 3.2.1 Add IP Address + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0xC001 | Length = Variable | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF-Request Correlation ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Parameter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * 3.2.2 Delete IP Address + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0xC002 | Length = Variable | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF-Request Correlation ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Parameter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc, + union sctp_addr *laddr, + struct sockaddr *addrs, + int addrcnt, + __u16 flags) +{ + sctp_addip_param_t param; + struct sctp_chunk *retval; + union sctp_addr_param addr_param; + union sctp_addr *addr; + void *addr_buf; + struct sctp_af *af; + int paramlen = sizeof(param); + int addr_param_len = 0; + int totallen = 0; + int i; + + /* Get total length of all the address parameters. */ + addr_buf = addrs; + for (i = 0; i < addrcnt; i++) { + addr = (union sctp_addr *)addr_buf; + af = sctp_get_af_specific(addr->v4.sin_family); + addr_param_len = af->to_addr_param(addr, &addr_param); + + totallen += paramlen; + totallen += addr_param_len; + + addr_buf += af->sockaddr_len; + } + + /* Create an asconf chunk with the required length. */ + retval = sctp_make_asconf(asoc, laddr, totallen); + if (!retval) + return NULL; + + /* Add the address parameters to the asconf chunk. */ + addr_buf = addrs; + for (i = 0; i < addrcnt; i++) { + addr = (union sctp_addr *)addr_buf; + af = sctp_get_af_specific(addr->v4.sin_family); + addr_param_len = af->to_addr_param(addr, &addr_param); + param.param_hdr.type = flags; + param.param_hdr.length = htons(paramlen + addr_param_len); + param.crr_id = i; + + sctp_addto_chunk(retval, paramlen, ¶m); + sctp_addto_chunk(retval, addr_param_len, &addr_param); + + addr_buf += af->sockaddr_len; + } + return retval; } -/* Convert an IP address in an SCTP param into a sockaddr_in. */ -/* Returns true if a valid conversion was possible. */ -int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa) +/* ADDIP + * 3.2.4 Set Primary IP Address + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type =0xC004 | Length = Variable | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF-Request Correlation ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Address Parameter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Create an ASCONF chunk with Set Primary IP address parameter. + */ +struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, + union sctp_addr *addr) { - switch (p.p->type) { - case SCTP_PARAM_IPV4_ADDRESS: - sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr); - sa->v4.sin_family = AF_INET; - break; + sctp_addip_param_t param; + struct sctp_chunk *retval; + int len = sizeof(param); + union sctp_addr_param addrparam; + int addrlen; + struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family); + + addrlen = af->to_addr_param(addr, &addrparam); + if (!addrlen) + return NULL; + len += addrlen; - case SCTP_PARAM_IPV6_ADDRESS: - *((struct in6_addr *)&sa->v4.sin_addr) - = p.v6->addr; - sa->v4.sin_family = AF_INET6; - break; + /* Create the chunk and make asconf header. */ + retval = sctp_make_asconf(asoc, addr, len); + if (!retval) + return NULL; - default: - return 0; - }; + param.param_hdr.type = SCTP_PARAM_SET_PRIMARY; + param.param_hdr.length = htons(len); + param.crr_id = 0; - return 1; + sctp_addto_chunk(retval, sizeof(param), ¶m); + sctp_addto_chunk(retval, addrlen, &addrparam); + + return retval; } -/* Convert a sockaddr_in to an IP address in an SCTP param. - * Returns len if a valid conversion was possible. +/* ADDIP 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type = 0x80 | Chunk Flags | Chunk Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Serial Number | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF Parameter Response#1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * \ \ + * / .... / + * \ \ + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ASCONF Parameter Response#N | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Create an ASCONF_ACK chunk with enough space for the parameter responses. */ -int sockaddr2sctp_addr(const union sctp_addr *sa, sctp_addr_param_t *p) +struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc, + __u32 serial, int vparam_len) { - int len = 0; + sctp_addiphdr_t asconf; + struct sctp_chunk *retval; + int length = sizeof(asconf) + vparam_len; - switch (sa->v4.sin_family) { - case AF_INET: - p->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS; - p->v4.param_hdr.length = ntohs(sizeof(sctp_ipv4addr_param_t)); - len = sizeof(sctp_ipv4addr_param_t); - p->v4.addr.s_addr = sa->v4.sin_addr.s_addr; - break; - - case AF_INET6: - p->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS; - p->v6.param_hdr.length = ntohs(sizeof(sctp_ipv6addr_param_t)); - len = sizeof(sctp_ipv6addr_param_t); - p->v6.addr = *(&sa->v6.sin6_addr); + /* Create the chunk. */ + retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF_ACK, 0, length); + if (!retval) + return NULL; + + asconf.serial = htonl(serial); + + retval->subh.addip_hdr = + sctp_addto_chunk(retval, sizeof(asconf), &asconf); + + return retval; +} + +/* Add response parameters to an ASCONF_ACK chunk. */ +static void sctp_add_asconf_response(struct sctp_chunk *chunk, __u32 crr_id, + __u16 err_code, sctp_addip_param_t *asconf_param) +{ + sctp_addip_param_t ack_param; + sctp_errhdr_t err_param; + int asconf_param_len = 0; + int err_param_len = 0; + __u16 response_type; + + if (SCTP_ERROR_NO_ERROR == err_code) { + response_type = SCTP_PARAM_SUCCESS_REPORT; + } else { + response_type = SCTP_PARAM_ERR_CAUSE; + err_param_len = sizeof(err_param); + if (asconf_param) + asconf_param_len = + ntohs(asconf_param->param_hdr.length); + } + + /* Add Success Indication or Error Cause Indication parameter. */ + ack_param.param_hdr.type = response_type; + ack_param.param_hdr.length = htons(sizeof(ack_param) + + err_param_len + + asconf_param_len); + ack_param.crr_id = crr_id; + sctp_addto_chunk(chunk, sizeof(ack_param), &ack_param); + + if (SCTP_ERROR_NO_ERROR == err_code) + return; + + /* Add Error Cause parameter. */ + err_param.cause = err_code; + err_param.length = htons(err_param_len + asconf_param_len); + sctp_addto_chunk(chunk, err_param_len, &err_param); + + /* Add the failed TLV copied from ASCONF chunk. */ + if (asconf_param) + sctp_addto_chunk(chunk, asconf_param_len, asconf_param); +} + +/* Process a asconf parameter. */ +static __u16 sctp_process_asconf_param(struct sctp_association *asoc, + struct sctp_chunk *asconf, + sctp_addip_param_t *asconf_param) +{ + struct sctp_transport *peer; + struct sctp_af *af; + union sctp_addr addr; + struct list_head *pos; + union sctp_addr_param *addr_param; + + addr_param = (union sctp_addr_param *) + ((void *)asconf_param + sizeof(sctp_addip_param_t)); + + af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + if (unlikely(!af)) + return SCTP_ERROR_INV_PARAM; + + af->from_addr_param(&addr, addr_param, asoc->peer.port, 0); + switch (asconf_param->param_hdr.type) { + case SCTP_PARAM_ADD_IP: + /* ADDIP 4.3 D9) If an endpoint receives an ADD IP address + * request and does not have the local resources to add this + * new address to the association, it MUST return an Error + * Cause TLV set to the new error code 'Operation Refused + * Due to Resource Shortage'. + */ + + peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC); + if (!peer) + return SCTP_ERROR_RSRC_LOW; + + /* Start the heartbeat timer. */ + if (!mod_timer(&peer->hb_timer, sctp_transport_timeout(peer))) + sctp_transport_hold(peer); + break; + case SCTP_PARAM_DEL_IP: + /* ADDIP 4.3 D7) If a request is received to delete the + * last remaining IP address of a peer endpoint, the receiver + * MUST send an Error Cause TLV with the error cause set to the + * new error code 'Request to Delete Last Remaining IP Address'. + */ + pos = asoc->peer.transport_addr_list.next; + if (pos->next == &asoc->peer.transport_addr_list) + return SCTP_ERROR_DEL_LAST_IP; + + /* ADDIP 4.3 D8) If a request is received to delete an IP + * address which is also the source address of the IP packet + * which contained the ASCONF chunk, the receiver MUST reject + * this request. To reject the request the receiver MUST send + * an Error Cause TLV set to the new error code 'Request to + * Delete Source IP Address' + */ + if (sctp_cmp_addr_exact(sctp_source(asconf), &addr)) + return SCTP_ERROR_DEL_SRC_IP; + + sctp_assoc_del_peer(asoc, &addr); break; + case SCTP_PARAM_SET_PRIMARY: + peer = sctp_assoc_lookup_paddr(asoc, &addr); + if (!peer) + return SCTP_ERROR_INV_PARAM; + sctp_assoc_set_primary(asoc, peer); + break; default: - printk(KERN_WARNING "sockaddr2sctp_addr: Illegal family %d.\n", - sa->v4.sin_family); - return 0; - }; + return SCTP_ERROR_INV_PARAM; + break; + } + + return SCTP_ERROR_NO_ERROR; +} + +/* Process an incoming ASCONF chunk with the next expected serial no. and + * return an ASCONF_ACK chunk to be sent in response. + */ +struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, + struct sctp_chunk *asconf) +{ + sctp_addiphdr_t *hdr; + union sctp_addr_param *addr_param; + sctp_addip_param_t *asconf_param; + struct sctp_chunk *asconf_ack; + + __u16 err_code; + int length = 0; + int chunk_len = asconf->skb->len; + __u32 serial; + int all_param_pass = 1; + + hdr = (sctp_addiphdr_t *)asconf->skb->data; + serial = ntohl(hdr->serial); + + /* Skip the addiphdr and store a pointer to address parameter. */ + length = sizeof(sctp_addiphdr_t); + addr_param = (union sctp_addr_param *)(asconf->skb->data + length); + chunk_len -= length; + + /* Skip the address parameter and store a pointer to the first + * asconf paramter. + */ + length = ntohs(addr_param->v4.param_hdr.length); + asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); + chunk_len -= length; + + /* create an ASCONF_ACK chunk. + * Based on the definitions of parameters, we know that the size of + * ASCONF_ACK parameters are less than or equal to the twice of ASCONF + * paramters. + */ + asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 2); + if (!asconf_ack) + goto done; + + /* Process the TLVs contained within the ASCONF chunk. */ + while (chunk_len > 0) { + err_code = sctp_process_asconf_param(asoc, asconf, + asconf_param); + /* ADDIP 4.1 A7) + * If an error response is received for a TLV parameter, + * all TLVs with no response before the failed TLV are + * considered successful if not reported. All TLVs after + * the failed response are considered unsuccessful unless + * a specific success indication is present for the parameter. + */ + if (SCTP_ERROR_NO_ERROR != err_code) + all_param_pass = 0; + + if (!all_param_pass) + sctp_add_asconf_response(asconf_ack, + asconf_param->crr_id, err_code, + asconf_param); + + /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add + * an IP address sends an 'Out of Resource' in its response, it + * MUST also fail any subsequent add or delete requests bundled + * in the ASCONF. + */ + if (SCTP_ERROR_RSRC_LOW == err_code) + goto done; - return len; + /* Move to the next ASCONF param. */ + length = ntohs(asconf_param->param_hdr.length); + asconf_param = (sctp_addip_param_t *)((void *)asconf_param + + length); + chunk_len -= length; + } + +done: + asoc->peer.addip_serial++; + + /* If we are sending a new ASCONF_ACK hold a reference to it in assoc + * after freeing the reference to old asconf ack if any. + */ + if (asconf_ack) { + if (asoc->addip_last_asconf_ack) + sctp_chunk_free(asoc->addip_last_asconf_ack); + + sctp_chunk_hold(asconf_ack); + asoc->addip_last_asconf_ack = asconf_ack; + } + + return asconf_ack; +} + +/* Process a asconf parameter that is successfully acked. */ +static int sctp_asconf_param_success(struct sctp_association *asoc, + sctp_addip_param_t *asconf_param) +{ + struct sctp_af *af; + union sctp_addr addr; + struct sctp_bind_addr *bp = &asoc->base.bind_addr; + union sctp_addr_param *addr_param; + int retval = 0; + + addr_param = (union sctp_addr_param *) + ((void *)asconf_param + sizeof(sctp_addip_param_t)); + + /* We have checked the packet before, so we do not check again. */ + af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type)); + af->from_addr_param(&addr, addr_param, bp->port, 0); + + switch (asconf_param->param_hdr.type) { + case SCTP_PARAM_ADD_IP: + sctp_local_bh_disable(); + sctp_write_lock(&asoc->base.addr_lock); + retval = sctp_add_bind_addr(bp, &addr, GFP_ATOMIC); + sctp_write_unlock(&asoc->base.addr_lock); + sctp_local_bh_enable(); + break; + case SCTP_PARAM_DEL_IP: + sctp_local_bh_disable(); + sctp_write_lock(&asoc->base.addr_lock); + retval = sctp_del_bind_addr(bp, &addr); + sctp_write_unlock(&asoc->base.addr_lock); + sctp_local_bh_enable(); + break; + default: + break; + } + + return retval; +} + +/* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk + * for the given asconf parameter. If there is no response for this parameter, + * return the error code based on the third argument 'no_err'. + * ADDIP 4.1 + * A7) If an error response is received for a TLV parameter, all TLVs with no + * response before the failed TLV are considered successful if not reported. + * All TLVs after the failed response are considered unsuccessful unless a + * specific success indication is present for the parameter. + */ +static __u16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack, + sctp_addip_param_t *asconf_param, + int no_err) +{ + sctp_addip_param_t *asconf_ack_param; + sctp_errhdr_t *err_param; + int length; + int asconf_ack_len = asconf_ack->skb->len; + __u16 err_code; + + if (no_err) + err_code = SCTP_ERROR_NO_ERROR; + else + err_code = SCTP_ERROR_REQ_REFUSED; + + /* Skip the addiphdr from the asconf_ack chunk and store a pointer to + * the first asconf_ack parameter. + */ + length = sizeof(sctp_addiphdr_t); + asconf_ack_param = (sctp_addip_param_t *)(asconf_ack->skb->data + + length); + asconf_ack_len -= length; + + while (asconf_ack_len > 0) { + if (asconf_ack_param->crr_id == asconf_param->crr_id) { + switch(asconf_ack_param->param_hdr.type) { + case SCTP_PARAM_SUCCESS_REPORT: + return SCTP_ERROR_NO_ERROR; + case SCTP_PARAM_ERR_CAUSE: + length = sizeof(sctp_addip_param_t); + err_param = (sctp_errhdr_t *) + ((void *)asconf_ack_param + length); + asconf_ack_len -= length; + if (asconf_ack_len > 0) + return err_param->cause; + else + return SCTP_ERROR_INV_PARAM; + break; + default: + return SCTP_ERROR_INV_PARAM; + } + } + + length = ntohs(asconf_ack_param->param_hdr.length); + asconf_ack_param = (sctp_addip_param_t *) + ((void *)asconf_ack_param + length); + asconf_ack_len -= length; + } + + return err_code; +} + +/* Process an incoming ASCONF_ACK chunk against the cached last ASCONF chunk. */ +int sctp_process_asconf_ack(struct sctp_association *asoc, + struct sctp_chunk *asconf_ack) +{ + struct sctp_chunk *asconf = asoc->addip_last_asconf; + union sctp_addr_param *addr_param; + sctp_addip_param_t *asconf_param; + int length = 0; + int asconf_len = asconf->skb->len; + int all_param_pass = 0; + int no_err = 1; + int retval = 0; + __u16 err_code = SCTP_ERROR_NO_ERROR; + + /* Skip the chunkhdr and addiphdr from the last asconf sent and store + * a pointer to address parameter. + */ + length = sizeof(sctp_addip_chunk_t); + addr_param = (union sctp_addr_param *)(asconf->skb->data + length); + asconf_len -= length; + + /* Skip the address parameter in the last asconf sent and store a + * pointer to the first asconf paramter. + */ + length = ntohs(addr_param->v4.param_hdr.length); + asconf_param = (sctp_addip_param_t *)((void *)addr_param + length); + asconf_len -= length; + + /* ADDIP 4.1 + * A8) If there is no response(s) to specific TLV parameter(s), and no + * failures are indicated, then all request(s) are considered + * successful. + */ + if (asconf_ack->skb->len == sizeof(sctp_addiphdr_t)) + all_param_pass = 1; + + /* Process the TLVs contained in the last sent ASCONF chunk. */ + while (asconf_len > 0) { + if (all_param_pass) + err_code = SCTP_ERROR_NO_ERROR; + else { + err_code = sctp_get_asconf_response(asconf_ack, + asconf_param, + no_err); + if (no_err && (SCTP_ERROR_NO_ERROR != err_code)) + no_err = 0; + } + + switch (err_code) { + case SCTP_ERROR_NO_ERROR: + retval = sctp_asconf_param_success(asoc, asconf_param); + break; + + case SCTP_ERROR_RSRC_LOW: + retval = 1; + break; + + case SCTP_ERROR_INV_PARAM: + /* Disable sending this type of asconf parameter in + * future. + */ + asoc->peer.addip_disabled_mask |= + asconf_param->param_hdr.type; + break; + + case SCTP_ERROR_REQ_REFUSED: + case SCTP_ERROR_DEL_LAST_IP: + case SCTP_ERROR_DEL_SRC_IP: + default: + break; + } + + /* Skip the processed asconf parameter and move to the next + * one. + */ + length = ntohs(asconf_param->param_hdr.length); + asconf_param = (sctp_addip_param_t *)((void *)asconf_param + + length); + asconf_len -= length; + } + + /* Free the cached last sent asconf chunk. */ + sctp_chunk_free(asconf); + asoc->addip_last_asconf = NULL; + + /* Send the next asconf chunk from the addip chunk queue. */ + asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks); + if (asconf) { + /* Hold the chunk until an ASCONF_ACK is received. */ + sctp_chunk_hold(asconf); + if (sctp_primitive_ASCONF(asoc, asconf)) + sctp_chunk_free(asconf); + else + asoc->addip_last_asconf = asconf; + } + + return retval; } diff -urN linux-2.4.25/net/sctp/sm_sideeffect.c linux-2.4.26/net/sctp/sm_sideeffect.c --- linux-2.4.25/net/sctp/sm_sideeffect.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/sm_sideeffect.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2002 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -81,11 +81,11 @@ * This element represents the lowest TSN number in the datagram * that was originally marked with the CE bit. */ -static sctp_chunk_t *sctp_do_ecn_ecne_work(struct sctp_association *asoc, +static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc, __u32 lowest_tsn, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Our previously transmitted packet ran into some congestion * so we should take action by reducing cwnd and ssthresh @@ -229,7 +229,7 @@ transport, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -269,7 +269,7 @@ (void *)timeout_type, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -294,6 +294,12 @@ sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); } +void sctp_generate_t4_rto_event(unsigned long data) +{ + struct sctp_association *asoc = (struct sctp_association *) data; + sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO); +} + void sctp_generate_t5_shutdown_guard_event(unsigned long data) { struct sctp_association *asoc = (struct sctp_association *)data; @@ -339,7 +345,7 @@ transport, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -359,6 +365,7 @@ sctp_generate_t1_init_event, sctp_generate_t2_shutdown_event, NULL, + sctp_generate_t4_rto_event, sctp_generate_t5_shutdown_guard_event, sctp_generate_heartbeat_event, sctp_generate_sack_event, @@ -415,7 +422,8 @@ struct sctp_ulpevent *event; event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, - 0, 0, 0, GFP_ATOMIC); + (__u16)error, 0, 0, + GFP_ATOMIC); if (event) sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, @@ -528,7 +536,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, struct sctp_transport *t, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { sctp_sender_hb_info_t *hbinfo; @@ -596,7 +604,7 @@ */ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, - sctp_chunk_t *chunk) + struct sctp_chunk *chunk) { struct sctp_transport *t; @@ -607,33 +615,30 @@ } /* Helper function to change the state of an association. */ -static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc, +static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc, sctp_state_t state) { - struct sock *sk = asoc->base.sk; - struct sctp_opt *sp = sctp_sk(sk); asoc->state = state; - asoc->state_timestamp = jiffies; - if (SCTP_SOCKET_TCP == sp->type) { - /* Change the sk->state of a TCP-style socket that has + if (sctp_style(sk, TCP)) { + /* Change the sk->sk_state of a TCP-style socket that has * sucessfully completed a connect() call. */ - if ((SCTP_STATE_ESTABLISHED == asoc->state) && - (SCTP_SS_CLOSED == sk->state)) - sk->state = SCTP_SS_ESTABLISHED; + if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) + sk->sk_state = SCTP_SS_ESTABLISHED; /* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */ - if (SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state) - sk->shutdown |= RCV_SHUTDOWN; - + if (sctp_state(asoc, SHUTDOWN_RECEIVED) && + sctp_sstate(sk, ESTABLISHED)) + sk->sk_shutdown |= RCV_SHUTDOWN; } - if ((SCTP_STATE_ESTABLISHED == asoc->state) || - (SCTP_STATE_CLOSED == asoc->state) || - (SCTP_STATE_SHUTDOWN_RECEIVED == asoc->state)) { + if (sctp_state(asoc, ESTABLISHED) || + sctp_state(asoc, CLOSED) || + sctp_state(asoc, SHUTDOWN_RECEIVED)) { /* Wake up any processes waiting in the asoc's wait queue in * sctp_wait_for_connect() or sctp_wait_for_sndbuf(). */ @@ -646,30 +651,84 @@ * For a UDP-style socket, the waiters are woken up by the * notifications. */ - if (SCTP_SOCKET_UDP != sp->type) - sk->state_change(sk); + if (!sctp_style(sk, UDP)) + sk->sk_state_change(sk); } - } /* Helper function to delete an association. */ static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds, - struct sctp_association *asoc) + struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; /* If it is a non-temporary association belonging to a TCP-style - * listening socket, do not free it so that accept() can pick it - * up later. - */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_SS_LISTENING == sk->state) && (!asoc->temp)) + * listening socket that is not closed, do not free it so that accept() + * can pick it up later. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && + (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK)) return; sctp_unhash_established(asoc); sctp_association_free(asoc); } +/* + * ADDIP Section 4.1 ASCONF Chunk Procedures + * A4) Start a T-4 RTO timer, using the RTO value of the selected + * destination address (we use active path instead of primary path just + * because primary path may be inactive. + */ +static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc, + struct sctp_chunk *chunk) +{ + struct sctp_transport *t; + + t = asoc->peer.active_path; + asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto; + chunk->transport = t; +} + +/* Process an incoming Operation Error Chunk. */ +static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds, + struct sctp_association *asoc, + struct sctp_chunk *chunk) +{ + struct sctp_operr_chunk *operr_chunk; + struct sctp_errhdr *err_hdr; + + operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr; + err_hdr = &operr_chunk->err_hdr; + + switch (err_hdr->cause) { + case SCTP_ERROR_UNKNOWN_CHUNK: + { + struct sctp_chunkhdr *unk_chunk_hdr; + + unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable; + switch (unk_chunk_hdr->type) { + /* ADDIP 4.1 A9) If the peer responds to an ASCONF with an + * ERROR chunk reporting that it did not recognized the ASCONF + * chunk type, the sender of the ASCONF MUST NOT send any + * further ASCONF chunks and MUST stop its T-4 timer. + */ + case SCTP_CID_ASCONF: + asoc->peer.asconf_capable = 0; + sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + break; + default: + break; + } + break; + } + default: + break; + } +} + /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -706,7 +765,7 @@ int gfp) { sctp_cmd_seq_t commands; - sctp_sm_table_entry_t *state_fn; + const sctp_sm_table_entry_t *state_fn; sctp_disposition_t status; int error = 0; typedef const char *(printfn_t)(sctp_subtype_t); @@ -837,17 +896,18 @@ int error = 0; int force; sctp_cmd_t *cmd; - sctp_chunk_t *new_obj; - sctp_chunk_t *chunk = NULL; + struct sctp_chunk *new_obj; + struct sctp_chunk *chunk = NULL; struct sctp_packet *packet; struct list_head *pos; struct timer_list *timer; unsigned long timeout; struct sctp_transport *t; sctp_sackhdr_t sackh; + int local_cork = 0; - if(SCTP_EVENT_T_TIMEOUT != event_type) - chunk = (sctp_chunk_t *) event_arg; + if (SCTP_EVENT_T_TIMEOUT != event_type) + chunk = (struct sctp_chunk *) event_arg; /* Note: This whole file is a huge candidate for rework. * For example, each command could either have its own handler, so @@ -864,6 +924,10 @@ case SCTP_CMD_NEW_ASOC: /* Register a new association. */ + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } asoc = cmd->obj.ptr; /* Register with the endpoint. */ sctp_endpoint_add_asoc(ep, asoc); @@ -878,7 +942,11 @@ sctp_outq_teardown(&asoc->outqueue); break; - case SCTP_CMD_DELETE_TCB: + case SCTP_CMD_DELETE_TCB: + if (local_cork) { + sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; + } /* Delete the current association. */ sctp_cmd_delete_tcb(commands, asoc); asoc = NULL; @@ -936,7 +1004,7 @@ new_obj = sctp_make_cookie_echo(asoc, chunk); if (!new_obj) { if (cmd->obj.ptr) - sctp_free_chunk(cmd->obj.ptr); + sctp_chunk_free(cmd->obj.ptr); goto nomem; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, @@ -957,7 +1025,7 @@ asoc->overall_error_count = 0; /* Generate a SHUTDOWN chunk. */ - new_obj = sctp_make_shutdown(asoc); + new_obj = sctp_make_shutdown(asoc, chunk); if (!new_obj) goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, @@ -982,9 +1050,13 @@ break; case SCTP_CMD_REPLY: + /* If an caller has not already corked, do cork. */ + if (!asoc->outqueue.cork) { + sctp_outq_cork(&asoc->outqueue); + local_cork = 1; + } /* Send a chunk to our peer. */ - error = sctp_outq_tail(&asoc->outqueue, - cmd->obj.ptr); + error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr); break; case SCTP_CMD_SEND_PKT: @@ -1002,7 +1074,8 @@ case SCTP_CMD_TRANSMIT: /* Kick start transmission. */ - error = sctp_outq_flush(&asoc->outqueue, 0); + error = sctp_outq_uncork(&asoc->outqueue); + local_cork = 0; break; case SCTP_CMD_ECN_CE: @@ -1167,19 +1240,28 @@ GFP_ATOMIC); break; + case SCTP_CMD_SETUP_T4: + sctp_cmd_setup_t4(commands, asoc, cmd->obj.ptr); + break; + + case SCTP_CMD_PROCESS_OPERR: + sctp_cmd_process_operr(commands, asoc, chunk); + break; default: printk(KERN_WARNING "Impossible command: %u, %p\n", cmd->verb, cmd->obj.ptr); break; }; if (error) - return error; + break; } +out: + if (local_cork) + sctp_outq_uncork(&asoc->outqueue); return error; - nomem: error = -ENOMEM; - return error; + goto out; } diff -urN linux-2.4.25/net/sctp/sm_statefuns.c linux-2.4.26/net/sctp/sm_statefuns.c --- linux-2.4.25/net/sctp/sm_statefuns.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/sm_statefuns.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2002 International Business Machines, Corp. * Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2002 Nokia Corp. * @@ -45,6 +45,8 @@ * Dajiang Zhang * Daisy Chang * Ardelle Fan + * Ryan Layer + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -101,7 +103,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; /* RFC 2960 6.10 Bundling @@ -185,10 +187,10 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; struct sctp_association *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; struct sock *sk; @@ -212,9 +214,9 @@ * on the TCP-style socket exceed the max backlog, respond with an * ABORT. */ - if ((SCTP_SS_LISTENING != sk->state) || - ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (sk->ack_backlog >= sk->max_ack_backlog))) + if (!sctp_sstate(sk, LISTENING) || + (sctp_style(sk, TCP) && + (sk->sk_ack_backlog >= sk->sk_max_ack_backlog))) return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); /* Verify the INIT chunk before processing it. */ @@ -232,7 +234,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -303,7 +305,7 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); @@ -320,7 +322,7 @@ nomem_ack: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); nomem_init: sctp_association_free(new_asoc); nomem: @@ -361,10 +363,10 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_init_chunk_t *initchunk; __u32 init_tag; - sctp_chunk_t *err_chunk; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_disposition_t ret; @@ -386,7 +388,7 @@ * error and close the association by transmitting an ABORT. */ if (!init_tag) { - sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0); + struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0); if (!reply) goto nomem; @@ -416,7 +418,7 @@ ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); if (packet) { sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, @@ -519,13 +521,13 @@ const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_association *new_asoc; sctp_init_chunk_t *peer_init; - sctp_chunk_t *repl; + struct sctp_chunk *repl; struct sctp_ulpevent *ev; int error = 0; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, respond with an ABORT. @@ -537,7 +539,7 @@ * are in good shape. */ chunk->subh.cookie_hdr = - (sctp_signed_cookie_t *)chunk->skb->data; + (struct sctp_signed_cookie *)chunk->skb->data; skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); @@ -623,7 +625,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem_repl: nomem_init: sctp_association_free(new_asoc); @@ -704,7 +706,7 @@ sctp_cmd_seq_t *commands) { struct sctp_transport *transport = (struct sctp_transport *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *reply; sctp_sender_hb_info_t hbinfo; size_t paylen = 0; @@ -738,7 +740,7 @@ { struct sctp_transport *transport = (struct sctp_transport *) arg; - if (asoc->overall_error_count >= asoc->overall_error_threshold) { + if (asoc->overall_error_count > asoc->max_retrans) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -801,8 +803,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; size_t paylen = 0; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure @@ -868,7 +870,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; union sctp_addr from_addr; struct sctp_transport *link; sctp_sender_hb_info_t *hbinfo; @@ -919,24 +921,25 @@ * condition. */ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, - sctp_chunk_t *init, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { int len; struct sctp_packet *pkt; - sctp_addr_param_t *addrparm; - sctp_errhdr_t *errhdr; + union sctp_addr_param *addrparm; + struct sctp_errhdr *errhdr; struct sctp_endpoint *ep; - char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; + char buffer[sizeof(struct sctp_errhdr)+sizeof(union sctp_addr_param)]; + struct sctp_af *af = sctp_get_af_specific(ssa->v4.sin_family); /* Build the error on the stack. We are way to malloc crazy * throughout the code today. */ - errhdr = (sctp_errhdr_t *)buffer; - addrparm = (sctp_addr_param_t *)errhdr->variable; + errhdr = (struct sctp_errhdr *)buffer; + addrparm = (union sctp_addr_param *)errhdr->variable; /* Copy into a parm format. */ - len = sockaddr2sctp_addr(ssa, addrparm); + len = af->to_addr_param(ssa, addrparm); len += sizeof(sctp_errhdr_t); errhdr->cause = SCTP_ERROR_RESTART; @@ -971,7 +974,7 @@ */ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, const struct sctp_association *asoc, - sctp_chunk_t *init, + struct sctp_chunk *init, sctp_cmd_seq_t *commands) { struct sctp_transport *new_addr, *addr; @@ -1112,10 +1115,10 @@ void *arg, sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *repl; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *repl; struct sctp_association *new_asoc; - sctp_chunk_t *err_chunk; + struct sctp_chunk *err_chunk; struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; int len; @@ -1191,7 +1194,7 @@ * since there are no peer addresses to check against. * Upon return an ABORT will have been sent if needed. */ - if (asoc->state != SCTP_STATE_COOKIE_WAIT) { + if (!sctp_state(asoc, COOKIE_WAIT)) { if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { retval = SCTP_DISPOSITION_CONSUME; @@ -1238,7 +1241,6 @@ * parameter type. */ sctp_addto_chunk(repl, len, unk_param); - sctp_free_chunk(err_chunk); } sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); @@ -1254,7 +1256,7 @@ cleanup: if (err_chunk) - sctp_free_chunk(err_chunk); + sctp_chunk_free(err_chunk); return retval; nomem: retval = SCTP_DISPOSITION_NOMEM; @@ -1377,13 +1379,13 @@ */ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - sctp_chunk_t *chunk, + struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. @@ -1429,7 +1431,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1444,13 +1446,13 @@ /* This case represents an initialization collision. */ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - sctp_chunk_t *chunk, + struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, struct sctp_association *new_asoc) { sctp_init_chunk_t *peer_init; struct sctp_ulpevent *ev; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* new_asoc is a brand-new association, so these are not yet * side effects--it is safe to run them here. @@ -1492,7 +1494,7 @@ return SCTP_DISPOSITION_CONSUME; nomem_ev: - sctp_free_chunk(repl); + sctp_chunk_free(repl); nomem: return SCTP_DISPOSITION_NOMEM; } @@ -1507,10 +1509,10 @@ */ /* This case represents an initialization collision. */ static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep, - const struct sctp_association *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - struct sctp_association *new_asoc) + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { /* The cookie should be silently discarded. * The endpoint SHOULD NOT change states and should leave @@ -1528,13 +1530,13 @@ */ /* This case represents an initialization collision. */ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep, - const struct sctp_association *asoc, - sctp_chunk_t *chunk, - sctp_cmd_seq_t *commands, - struct sctp_association *new_asoc) + const struct sctp_association *asoc, + struct sctp_chunk *chunk, + sctp_cmd_seq_t *commands, + struct sctp_association *new_asoc) { struct sctp_ulpevent *ev = NULL; - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* Clarification from Implementor's Guide: * D) When both local and remote tags match the endpoint should @@ -1610,16 +1612,16 @@ sctp_cmd_seq_t *commands) { sctp_disposition_t retval; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_association *new_asoc; int error = 0; char action; - sctp_chunk_t *err_chk_p; + struct sctp_chunk *err_chk_p; /* "Decode" the chunk. We have no optional parameters so we * are in good shape. */ - chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data; + chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); @@ -1708,7 +1710,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1731,7 +1733,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); @@ -1785,27 +1787,20 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_errhdr_t *err; - err = (sctp_errhdr_t *)(chunk->skb->data); - - /* If we have gotten too many failures, give up. */ - if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] > - asoc->max_init_attempts) { - /* INIT_FAILED will issue an ulpevent. */ - sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, - SCTP_U32(err->cause)); - return SCTP_DISPOSITION_DELETE_TCB; - } - /* Process the error here */ - switch (err->cause) { - case SCTP_ERROR_STALE_COOKIE: - return sctp_sf_do_5_2_6_stale(ep, asoc, type, arg, commands); - default: - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); + /* FUTURE FIXME: When PR-SCTP related and other optional + * parms are emitted, this will have to change to handle multiple + * errors. + */ + sctp_walk_errors(err, chunk->chunk_hdr) { + if (SCTP_ERROR_STALE_COOKIE == err->cause) + return sctp_sf_do_5_2_6_stale(ep, asoc, type, + arg, commands); } + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); } /* @@ -1839,14 +1834,14 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; time_t stale; sctp_cookie_preserve_param_t bht; sctp_errhdr_t *err; struct list_head *pos; struct sctp_transport *t; - sctp_chunk_t *reply; - sctp_bind_addr_t *bp; + struct sctp_chunk *reply; + struct sctp_bind_addr *bp; int attempts; attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1; @@ -1874,14 +1869,14 @@ * yield a higher probability of success on the reattempt. */ stale = ntohl(*(suseconds_t *)((u8 *)err + sizeof(sctp_errhdr_t))); - stale = stale << 1 / 1000; + stale = (stale * 2) / 1000; bht.param_hdr.type = SCTP_PARAM_COOKIE_PRESERVATIVE; bht.param_hdr.length = htons(sizeof(bht)); bht.lifespan_increment = htonl(stale); /* Build that new INIT chunk. */ - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht)); if (!reply) goto nomem; @@ -1954,23 +1949,24 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; + unsigned len; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + - sizeof(struct sctp_errhdr)))) + /* Check that chunk header looks valid. */ + len = ntohs(chunk->chunk_hdr->length); + if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; + /* ASSOC_FAILED will DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error)); SCTP_INC_STATS(SctpAborteds); SCTP_DEC_STATS(SctpCurrEstab); - /* BUG? This does not look complete... */ return SCTP_DISPOSITION_ABORT; } @@ -1985,7 +1981,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; + unsigned len; __u16 error = SCTP_ERROR_NO_ERROR; if (!sctp_vtag_verify_either(chunk, asoc)) @@ -1997,9 +1994,9 @@ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); - if (chunk && (ntohs(chunk->chunk_hdr->length) >= - (sizeof(struct sctp_chunkhdr) + - sizeof(struct sctp_errhdr)))) + /* Check that chunk header looks valid. */ + len = ntohs(chunk->chunk_hdr->length); + if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr)) error = ((sctp_errhdr_t *)chunk->skb->data)->cause; /* CMD_INIT_FAILED will DELETE_TCB. */ @@ -2064,9 +2061,10 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_shutdownhdr_t *sdh; sctp_disposition_t disposition; + struct sctp_ulpevent *ev; /* Convert the elaborate header. */ sdh = (sctp_shutdownhdr_t *)chunk->skb->data; @@ -2097,12 +2095,28 @@ arg, commands); } + if (SCTP_DISPOSITION_NOMEM == disposition) + goto out; + /* - verify, by checking the Cumulative TSN Ack field of the * chunk, that all its outstanding DATA chunks have been * received by the SHUTDOWN sender. */ sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); + + /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ + ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC); + if (!ev) { + disposition = SCTP_DISPOSITION_NOMEM; + goto out; + } + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + +out: return disposition; } @@ -2119,8 +2133,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; reply = sctp_make_shutdown_ack(asoc, chunk); if (NULL == reply) @@ -2174,7 +2188,7 @@ sctp_cmd_seq_t *commands) { sctp_cwrhdr_t *cwr; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2230,7 +2244,7 @@ sctp_cmd_seq_t *commands) { sctp_ecnehdr_t *ecne; - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure * that the value in the Verification Tag field of the @@ -2287,9 +2301,9 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; sctp_verb_t deliver; int tmp; @@ -2311,9 +2325,7 @@ skb_pull(chunk->skb, sizeof(sctp_datahdr_t)); tsn = ntohl(data_hdr->tsn); - SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn); - SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head); /* ASSERT: Now skb->data is really the user data. */ @@ -2328,9 +2340,13 @@ */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); @@ -2373,7 +2389,8 @@ * PMTU. In cases, such as loopback, this might be a rather * large spill over. */ - if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { + if (!asoc->rwnd || asoc->rwnd_over || + (datalen > asoc->rwnd + asoc->frag_point)) { /* If this is the next TSN, consider reneging to make * room. Note: Playing nice with a confused sender. A @@ -2545,9 +2562,9 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_datahdr_t *data_hdr; - sctp_chunk_t *err; + struct sctp_chunk *err; size_t datalen; int tmp; __u32 tsn; @@ -2583,9 +2600,13 @@ * chunk later. */ if (!chunk->ecn_ce_done) { + struct sctp_af *af; chunk->ecn_ce_done = 1; - if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) && - asoc->peer.ecn_capable) { + + af = sctp_get_af_specific( + ipver2af(chunk->skb->nh.iph->version)); + + if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) { /* Do real work as sideffect. */ sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, SCTP_U32(tsn)); @@ -2720,7 +2741,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_sackhdr_t *sackh; __u32 ctsn; @@ -2733,6 +2754,9 @@ /* Pull the SACK chunk from the data buffer */ sackh = sctp_sm_pull_sack(chunk); + /* Was this a bogus SACK? */ + if (!sackh) + return sctp_sf_pdiscard(ep, asoc, type, arg, commands); chunk->subh.sack_hdr = sackh; ctsn = ntohl(sackh->cum_tsn_ack); @@ -2782,8 +2806,8 @@ sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *abort; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -2827,7 +2851,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sctp_ulpevent *ev; while (chunk->chunk_end > chunk->skb->data) { @@ -2841,6 +2865,9 @@ sctp_ulpevent_free(ev); goto nomem; } + + sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR, + SCTP_CHUNK(chunk)); } return SCTP_DISPOSITION_CONSUME; @@ -2864,8 +2891,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *reply; struct sctp_ulpevent *ev; /* 10.2 H) SHUTDOWN COMPLETE notification @@ -2932,7 +2959,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; struct sk_buff *skb = chunk->skb; sctp_chunkhdr_t *ch; __u8 *ch_end; @@ -2984,8 +3011,8 @@ sctp_cmd_seq_t *commands) { struct sctp_packet *packet = NULL; - sctp_chunk_t *chunk = arg; - sctp_chunk_t *shut; + struct sctp_chunk *chunk = arg; + struct sctp_chunk *shut; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -3040,6 +3067,143 @@ return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands); } +/* ADDIP Section 4.2 Upon reception of an ASCONF Chunk. */ +sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = arg; + struct sctp_chunk *asconf_ack = NULL; + sctp_addiphdr_t *hdr; + __u32 serial; + + hdr = (sctp_addiphdr_t *)chunk->skb->data; + serial = ntohl(hdr->serial); + + /* ADDIP 4.2 C1) Compare the value of the serial number to the value + * the endpoint stored in a new association variable + * 'Peer-Serial-Number'. + */ + if (serial == asoc->peer.addip_serial + 1) { + /* ADDIP 4.2 C2) If the value found in the serial number is + * equal to the ('Peer-Serial-Number' + 1), the endpoint MUST + * do V1-V5. + */ + asconf_ack = sctp_process_asconf((struct sctp_association *) + asoc, chunk); + if (!asconf_ack) + return SCTP_DISPOSITION_NOMEM; + } else if (serial == asoc->peer.addip_serial) { + /* ADDIP 4.2 C3) If the value found in the serial number is + * equal to the value stored in the 'Peer-Serial-Number' + * IMPLEMENTATION NOTE: As an optimization a receiver may wish + * to save the last ASCONF-ACK for some predetermined period of * time and instead of re-processing the ASCONF (with the same + * serial number) it may just re-transmit the ASCONF-ACK. + */ + if (asoc->addip_last_asconf_ack) + asconf_ack = asoc->addip_last_asconf_ack; + else + return SCTP_DISPOSITION_DISCARD; + } else { + /* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since + * it must be either a stale packet or from an attacker. + */ + return SCTP_DISPOSITION_DISCARD; + } + + /* ADDIP 4.2 C5) In both cases C2 and C3 the ASCONF-ACK MUST be sent + * back to the source address contained in the IP header of the ASCONF + * being responded to. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(asconf_ack)); + + return SCTP_DISPOSITION_CONSUME; +} + +/* + * ADDIP Section 4.3 General rules for address manipulation + * When building TLV parameters for the ASCONF Chunk that will add or + * delete IP addresses the D0 to D13 rules should be applied: + */ +sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *asconf_ack = arg; + struct sctp_chunk *last_asconf = asoc->addip_last_asconf; + struct sctp_chunk *abort; + sctp_addiphdr_t *addip_hdr; + __u32 sent_serial, rcvd_serial; + + addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data; + rcvd_serial = ntohl(addip_hdr->serial); + + if (last_asconf) { + addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; + sent_serial = ntohl(addip_hdr->serial); + } else { + sent_serial = asoc->addip_serial - 1; + } + + /* D0) If an endpoint receives an ASCONF-ACK that is greater than or + * equal to the next serial number to be used but no ASCONF chunk is + * outstanding the endpoint MUST ABORT the association. Note that a + * sequence number is greater than if it is no more than 2^^31-1 + * larger than the current sequence number (using serial arithmetic). + */ + if (ADDIP_SERIAL_gte(rcvd_serial, sent_serial + 1) && + !(asoc->addip_last_asconf)) { + abort = sctp_make_abort(asoc, asconf_ack, + sizeof(sctp_errhdr_t)); + if (abort) { + sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(abort)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_U32(SCTP_ERROR_ASCONF_ACK)); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); + return SCTP_DISPOSITION_ABORT; + } + + if ((rcvd_serial == sent_serial) && asoc->addip_last_asconf) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + + if (!sctp_process_asconf_ack((struct sctp_association *)asoc, + asconf_ack)) + return SCTP_DISPOSITION_CONSUME; + + abort = sctp_make_abort(asoc, asconf_ack, + sizeof(sctp_errhdr_t)); + if (abort) { + sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(abort)); + } + /* We are going to ABORT, so we might as well stop + * processing the rest of the chunks in the packet. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_U32(SCTP_ERROR_ASCONF_ACK)); + SCTP_INC_STATS(SctpAborteds); + SCTP_DEC_STATS(SctpCurrEstab); + return SCTP_DISPOSITION_ABORT; + } + + return SCTP_DISPOSITION_DISCARD; +} + /* * Process an unknown chunk. * @@ -3069,8 +3233,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *unk_chunk = arg; - sctp_chunk_t *err_chunk; + struct sctp_chunk *unk_chunk = arg; + struct sctp_chunk *err_chunk; sctp_chunkhdr_t *hdr; SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk); @@ -3182,82 +3346,6 @@ return SCTP_DISPOSITION_CONSUME; } -#if 0 -/* - * We did something stupid but got lucky. Namely, we sent a HEARTBEAT - * before the association was all the way up and we did NOT get an - * ABORT. - * - * Log the fact and then process normally. - * - * Section: Not specified - * Verification Tag: 8.5 Verification Tag [Normal verification] - * Inputs - * (endpoint, asoc, chunk) - * - * Outputs - * (asoc, reply_msg, msg_up, timers, counters) - * - * The return value is the disposition of the chunk. - */ -sctp_disposition_t lucky(const struct sctp_endpoint *ep, - const struct sctp_association *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - - return SCTP_DISPOSITION_CONSUME; - -nomem: - return SCTP_DISPOSITION_NOMEM; -} -#endif /* 0 */ - -#if 0 -/* - * The other end is doing something very stupid. We'll ignore them - * after logging their idiocy. :-) - * - * Section: Not specified - * Verification Tag: 8.5 Verification Tag [Normal verification] - * Inputs - * (endpoint, asoc, chunk) - * - * Outputs - * (asoc, reply_msg, msg_up, timers, counters) - * - * The return value is the disposition of the chunk. - */ -sctp_disposition_t other_stupid(const struct sctp_endpoint *ep, - const struct sctp_association *asoc, - const sctp_subtype_t type, - void *arg, - sctp_cmd_seq_t *commands) -{ - sctp_chunk_t *chunk = arg; - - /* 8.5 When receiving an SCTP packet, the endpoint MUST ensure - * that the value in the Verification Tag field of the - * received SCTP packet matches its own Tag. ... - */ - if (chunk->sctp_hdr->vtag != asoc->c.my_vtag) - return sctp_sf_pdiscard(ep, asoc, type, arg, commands); - - return SCTP_DISPOSITION_CONSUME; - -nomem: - return SCTP_DISPOSITION_NOMEM; -} -#endif /* 0 */ /* * The other end is violating protocol. @@ -3348,7 +3436,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; + struct sctp_chunk *repl; /* The comment below says that we enter COOKIE-WAIT AFTER * sending the INIT, but that doesn't actually work in our @@ -3454,7 +3542,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = arg; + struct sctp_chunk *chunk = arg; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); return SCTP_DISPOSITION_CONSUME; @@ -3564,7 +3652,7 @@ * if necessary to fill gaps. */ struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; retval = SCTP_DISPOSITION_CONSUME; @@ -3697,7 +3785,7 @@ sctp_cmd_seq_t *commands) { struct msghdr *msg = arg; - sctp_chunk_t *abort; + struct sctp_chunk *abort; sctp_disposition_t retval; /* Stop T1-init timer */ @@ -3870,6 +3958,26 @@ } /* + * ADDIP Section 4.1 ASCONF Chunk Procedures + * When an endpoint has an ASCONF signaled change to be sent to the + * remote endpoint it should do A1 to A9 + */ +sctp_disposition_t sctp_sf_do_prm_asconf(const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = arg; + + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk)); + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk)); + return SCTP_DISPOSITION_CONSUME; +} + +/* * Ignore the primitive event * * The return value is the disposition of the primitive. @@ -3909,14 +4017,14 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply; + struct sctp_chunk *reply; /* Once all its outstanding data has been acknowledged, the * endpoint shall send a SHUTDOWN chunk to its peer including * in the Cumulative TSN Ack field the last sequential TSN it * has received from the peer. */ - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); if (!reply) goto nomem; @@ -3971,8 +4079,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *chunk = (sctp_chunk_t *) arg; - sctp_chunk_t *reply; + struct sctp_chunk *chunk = (struct sctp_chunk *) arg; + struct sctp_chunk *reply; /* If it has no more outstanding DATA chunks, the SHUTDOWN receiver * shall send a SHUTDOWN ACK ... @@ -4051,7 +4159,7 @@ { struct sctp_transport *transport = arg; - if (asoc->overall_error_count >= asoc->overall_error_threshold) { + if (asoc->overall_error_count >= asoc->max_retrans) { /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -4152,8 +4260,8 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *repl; - sctp_bind_addr_t *bp; + struct sctp_chunk *repl; + struct sctp_bind_addr *bp; sctp_event_timeout_t timer = (sctp_event_timeout_t) arg; int timeout; int attempts; @@ -4164,11 +4272,10 @@ SCTP_DEBUG_PRINTK("Timer T1 expired.\n"); - if ((timeout < asoc->max_init_timeo) && - (attempts < asoc->max_init_attempts)) { + if (attempts < asoc->max_init_attempts) { switch (timer) { case SCTP_EVENT_TIMEOUT_T1_INIT: - bp = (sctp_bind_addr_t *) &asoc->base.bind_addr; + bp = (struct sctp_bind_addr *) &asoc->base.bind_addr; repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0); break; @@ -4219,10 +4326,10 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); - if (asoc->overall_error_count >= asoc->overall_error_threshold) { + if (asoc->overall_error_count >= asoc->max_retrans) { /* Note: CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(SCTP_ERROR_NO_ERROR)); @@ -4233,7 +4340,7 @@ switch (asoc->state) { case SCTP_STATE_SHUTDOWN_SENT: - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); break; case SCTP_STATE_SHUTDOWN_ACK_SENT: @@ -4267,6 +4374,69 @@ return SCTP_DISPOSITION_NOMEM; } +/* + * ADDIP Section 4.1 ASCONF CHunk Procedures + * If the T4 RTO timer expires the endpoint should do B1 to B5 + */ +sctp_disposition_t sctp_sf_t4_timer_expire( + const struct sctp_endpoint *ep, + const struct sctp_association *asoc, + const sctp_subtype_t type, + void *arg, + sctp_cmd_seq_t *commands) +{ + struct sctp_chunk *chunk = asoc->addip_last_asconf; + struct sctp_transport *transport = chunk->transport; + + /* ADDIP 4.1 B1) Increment the error counters and perform path failure + * detection on the appropriate destination address as defined in + * RFC2960 [5] section 8.1 and 8.2. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport)); + + /* Reconfig T4 timer and transport. */ + sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk)); + + /* ADDIP 4.1 B2) Increment the association error counters and perform + * endpoint failure detection on the association as defined in + * RFC2960 [5] section 8.1 and 8.2. + * association error counter is incremented in SCTP_CMD_STRIKE. + */ + if (asoc->overall_error_count >= asoc->max_retrans) { + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, + SCTP_U32(SCTP_ERROR_NO_ERROR)); + SCTP_INC_STATS(SctpAborteds); + SCTP_INC_STATS(SctpCurrEstab); + return SCTP_DISPOSITION_ABORT; + } + + /* ADDIP 4.1 B3) Back-off the destination address RTO value to which + * the ASCONF chunk was sent by doubling the RTO timer value. + * This is done in SCTP_CMD_STRIKE. + */ + + /* ADDIP 4.1 B4) Re-transmit the ASCONF Chunk last sent and if possible + * choose an alternate destination address (please refer to RFC2960 + * [5] section 6.4.1). An endpoint MUST NOT add new parameters to this + * chunk, it MUST be the same (including its serial number) as the last + * ASCONF sent. + */ + sctp_chunk_hold(asoc->addip_last_asconf); + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(asoc->addip_last_asconf)); + + /* ADDIP 4.1 B5) Restart the T-4 RTO timer. Note that if a different + * destination is selected, then the RTO used will be that of the new + * destination address. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART, + SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO)); + + return SCTP_DISPOSITION_CONSUME; +} + /* sctpimpguide-05 Section 2.12.2 * The sender of the SHUTDOWN MAY also start an overall guard timer * 'T5-shutdown-guard' to bound the overall time for shutdown sequence. @@ -4279,7 +4449,7 @@ void *arg, sctp_cmd_seq_t *commands) { - sctp_chunk_t *reply = NULL; + struct sctp_chunk *reply = NULL; SCTP_DEBUG_PRINTK("Timer T5 expired.\n"); @@ -4399,22 +4569,27 @@ ********************************************************************/ /* Pull the SACK chunk based on the SACK header. */ -sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) +struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk) { - sctp_sackhdr_t *sack; + struct sctp_sackhdr *sack; + unsigned int len; __u16 num_blocks; __u16 num_dup_tsns; - /* FIXME: Protect ourselves from reading too far into + /* Protect ourselves from reading too far into * the skb from a bogus sender. */ - sack = (sctp_sackhdr_t *) chunk->skb->data; - skb_pull(chunk->skb, sizeof(sctp_sackhdr_t)); + sack = (struct sctp_sackhdr *) chunk->skb->data; num_blocks = ntohs(sack->num_gap_ack_blocks); num_dup_tsns = ntohs(sack->num_dup_tsns); + len = sizeof(struct sctp_sackhdr); + len = (num_blocks + num_dup_tsns) * sizeof(__u32); + if (len > chunk->skb->len) + return NULL; + + skb_pull(chunk->skb, len); - skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32)); return sack; } @@ -4423,12 +4598,12 @@ */ struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - sctp_chunk_t *chunk, + struct sctp_chunk *chunk, const void *payload, size_t paylen) { struct sctp_packet *packet; - sctp_chunk_t *abort; + struct sctp_chunk *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -4458,7 +4633,7 @@ /* Allocate a packet for responding in the OOTB conditions. */ struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc, - const sctp_chunk_t *chunk) + const struct sctp_chunk *chunk) { struct sctp_packet *packet; struct sctp_transport *transport; @@ -4476,13 +4651,21 @@ if (asoc) { vtag = asoc->peer.i.init_tag; } else { - /* Special case the INIT as there is no vtag yet. */ - if (SCTP_CID_INIT == chunk->chunk_hdr->type) { + /* Special case the INIT and stale COOKIE_ECHO as there is no + * vtag yet. + */ + switch(chunk->chunk_hdr->type) { + case SCTP_CID_INIT: + { sctp_init_chunk_t *init; + init = (sctp_init_chunk_t *)chunk->chunk_hdr; vtag = ntohl(init->init_hdr.init_tag); - } else { + break; + } + default: vtag = ntohl(chunk->sctp_hdr->vtag); + break; } } @@ -4524,15 +4707,21 @@ /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep, const struct sctp_association *asoc, - const sctp_chunk_t *chunk, + const struct sctp_chunk *chunk, sctp_cmd_seq_t *commands, - sctp_chunk_t *err_chunk) + struct sctp_chunk *err_chunk) { struct sctp_packet *packet; if (err_chunk) { packet = sctp_ootb_pkt_new(asoc, chunk); if (packet) { + struct sctp_signed_cookie *cookie; + + /* Override the OOTB vtag from the cookie. */ + cookie = chunk->subh.cookie_hdr; + packet->vtag = cookie->c.peer_vtag; + /* Set the skb to the belonging sock for accounting. */ err_chunk->skb->sk = ep->base.sk; sctp_packet_append_chunk(packet, err_chunk); @@ -4540,6 +4729,6 @@ SCTP_PACKET(packet)); SCTP_INC_STATS(SctpOutCtrlChunks); } else - sctp_free_chunk (err_chunk); + sctp_chunk_free (err_chunk); } } diff -urN linux-2.4.25/net/sctp/sm_statetable.c linux-2.4.26/net/sctp/sm_statetable.c --- linux-2.4.25/net/sctp/sm_statetable.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/sm_statetable.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * @@ -49,7 +49,7 @@ #include #include -static sctp_sm_table_entry_t bug = { +static const sctp_sm_table_entry_t bug = { .fn = sctp_sf_bug, .name = "sctp_sf_bug" }; @@ -64,9 +64,9 @@ } \ return &_table[event_subtype._type][(int)state]; -sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, - sctp_state_t state, - sctp_subtype_t event_subtype) +const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, + sctp_state_t state, + sctp_subtype_t event_subtype) { switch (event_type) { case SCTP_EVENT_T_CHUNK: @@ -418,7 +418,7 @@ * * For base protocol (RFC 2960). */ -sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { +const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { TYPE_SCTP_DATA, TYPE_SCTP_INIT, TYPE_SCTP_INIT_ACK, @@ -436,53 +436,57 @@ TYPE_SCTP_SHUTDOWN_COMPLETE, }; /* state_fn_t chunk_event_table[][] */ -static sctp_sm_table_entry_t -chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = { - /* SCTP_STATE_EMPTY */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_CLOSED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_COOKIE_WAIT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_COOKIE_ECHOED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_ESTABLISHED */ - {.fn = sctp_sf_discard_chunk, - .name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"}, - /* SCTP_STATE_SHUTDOWN_PENDING */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_SENT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_RECEIVED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, -}; /* chunk asconf */ +#define TYPE_SCTP_ASCONF { \ + /* SCTP_STATE_EMPTY */ \ + {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {.fn = sctp_sf_do_asconf, .name = "sctp_sf_do_asconf"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_ASCONF */ -static sctp_sm_table_entry_t -chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { - /* SCTP_STATE_EMPTY */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_CLOSED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_COOKIE_WAIT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_COOKIE_ECHOED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_ESTABLISHED */ - {.fn = sctp_sf_discard_chunk, - .name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"}, - /* SCTP_STATE_SHUTDOWN_PENDING */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_SENT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_RECEIVED */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, - /* SCTP_STATE_SHUTDOWN_ACK_SENT */ - {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, -}; /* chunk asconf_ack */ +#define TYPE_SCTP_ASCONF_ACK { \ + /* SCTP_STATE_EMPTY */ \ + {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ + /* SCTP_STATE_CLOSED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {.fn = sctp_sf_do_asconf_ack, .name = "sctp_sf_do_asconf_ack"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ +} /* TYPE_SCTP_ASCONF_ACK */ + +/* The primary index for this table is the chunk type. + * The secondary index for this table is the state. + */ +const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = { + TYPE_SCTP_ASCONF, + TYPE_SCTP_ASCONF_ACK, +}; /*state_fn_t addip_chunk_event_table[][] */ -static sctp_sm_table_entry_t +static const sctp_sm_table_entry_t chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { /* SCTP_STATE_EMPTY */ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, @@ -627,16 +631,37 @@ .name = "sctp_sf_do_prm_requestheartbeat"}, \ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ +#define TYPE_SCTP_PRIMITIVE_ASCONF { \ + /* SCTP_STATE_EMPTY */ \ + {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {.fn = sctp_sf_do_prm_asconf, .name = "sctp_sf_do_prm_asconf"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \ +} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ /* The primary index for this table is the primitive type. * The secondary index for this table is the state. */ -sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { +const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = { TYPE_SCTP_PRIMITIVE_ASSOCIATE, TYPE_SCTP_PRIMITIVE_SHUTDOWN, TYPE_SCTP_PRIMITIVE_ABORT, TYPE_SCTP_PRIMITIVE_SEND, TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT, + TYPE_SCTP_PRIMITIVE_ASCONF, }; #define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ @@ -662,7 +687,7 @@ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \ } -sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { +const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { TYPE_SCTP_OTHER_NO_PENDING_TSN, }; @@ -771,6 +796,27 @@ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ } +#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ + /* SCTP_STATE_EMPTY */ \ + {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + /* SCTP_STATE_CLOSED */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_WAIT */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_COOKIE_ECHOED */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_ESTABLISHED */ \ + {.fn = sctp_sf_t4_timer_expire, .name = "sctp_sf_t4_timer_expire"}, \ + /* SCTP_STATE_SHUTDOWN_PENDING */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_SENT */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ + {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ +} + #define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \ /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ @@ -783,7 +829,7 @@ /* SCTP_STATE_ESTABLISHED */ \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ /* SCTP_STATE_SHUTDOWN_PENDING */ \ - {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ + {.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \ /* SCTP_STATE_SHUTDOWN_SENT */ \ {.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ @@ -856,34 +902,35 @@ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \ } -sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { +const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { TYPE_SCTP_EVENT_TIMEOUT_NONE, TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE, TYPE_SCTP_EVENT_TIMEOUT_T1_INIT, TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, + TYPE_SCTP_EVENT_TIMEOUT_T4_RTO, TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD, TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, TYPE_SCTP_EVENT_TIMEOUT_SACK, TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, }; -sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) +const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, + sctp_state_t state) { if (state > SCTP_STATE_MAX) return &bug; - if (cid >= 0 && cid <= SCTP_CID_BASE_MAX) { + if (cid >= 0 && cid <= SCTP_CID_BASE_MAX) return &chunk_event_table[cid][state]; - } - switch (cid) { - case SCTP_CID_ASCONF: - return &chunk_event_table_asconf[state]; + if (sctp_addip_enable) { + if (cid == SCTP_CID_ASCONF) + return &addip_chunk_event_table[0][state]; - case SCTP_CID_ASCONF_ACK: - return &chunk_event_table_asconf_ack[state]; - default: - return &chunk_event_table_unknown[state]; + if (cid == SCTP_CID_ASCONF_ACK) + return &addip_chunk_event_table[1][state]; } + + return &chunk_event_table_unknown[state]; } diff -urN linux-2.4.25/net/sctp/socket.c linux-2.4.26/net/sctp/socket.c --- linux-2.4.25/net/sctp/socket.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sctp/socket.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,6 +1,7 @@ -/* Copyright (c) 1999-2000 Cisco, Inc. +/* SCTP kernel reference Implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2002 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll @@ -48,6 +49,9 @@ * Sridhar Samudrala * Inaky Perez-Gonzalez * Ardelle Fan + * Ryan Layer + * Anup Pemmaiah + * Kevin Gao * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -62,6 +66,7 @@ #include #include #include +#include #include #include @@ -82,22 +87,30 @@ /* Forward declarations for internal helper functions. */ static int sctp_writeable(struct sock *sk); static inline int sctp_wspace(struct sctp_association *asoc); -static inline void sctp_set_owner_w(sctp_chunk_t *chunk); +static inline void sctp_set_owner_w(struct sctp_chunk *chunk); static void sctp_wfree(struct sk_buff *skb); static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p, - int msg_len); + size_t msg_len); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); static int sctp_wait_for_accept(struct sock *sk, long timeo); +static void sctp_wait_for_close(struct sock *sk, long timeo); static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int); -static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); -static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); +static int sctp_bindx_add(struct sock *, struct sockaddr *, int); +static int sctp_bindx_rem(struct sock *, struct sockaddr *, int); +static int sctp_send_asconf_add_ip(struct sock *, struct sockaddr *, int); +static int sctp_send_asconf_del_ip(struct sock *, struct sockaddr *, int); +static int sctp_send_asconf(struct sctp_association *asoc, + struct sctp_chunk *chunk); static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_autobind(struct sock *sk); static void sctp_sock_migrate(struct sock *, struct sock *, struct sctp_association *, sctp_socket_type_t); static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; +extern kmem_cache_t *sctp_bucket_cachep; +extern int sctp_assoc_valid(struct sock *sk, struct sctp_association *asoc); + /* Look up the association by its id. If this is not a UDP-style * socket, the ID field is always ignored. */ @@ -105,32 +118,61 @@ { struct sctp_association *asoc = NULL; - /* If this is not a UDP-style socket, assoc id should be - * ignored. - */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { + /* If this is not a UDP-style socket, assoc id should be ignored. */ + if (!sctp_style(sk, UDP)) { + /* Return NULL if the socket state is not ESTABLISHED. It + * could be a TCP-style listening socket or a socket which + * hasn't yet called connect() to establish an association. + */ + if (!sctp_sstate(sk, ESTABLISHED)) + return NULL; + + /* Get the first and the only association from the list. */ if (!list_empty(&sctp_sk(sk)->ep->asocs)) asoc = list_entry(sctp_sk(sk)->ep->asocs.next, struct sctp_association, asocs); return asoc; } - /* First, verify that this is a kernel address. */ - if (sctp_is_valid_kaddr((unsigned long) id)) { - struct sctp_association *temp; - - /* Verify that this _is_ an sctp_association - * data structure and if so, that the socket matches. - */ - temp = (struct sctp_association *)id; - if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && - (temp->base.sk == sk)) - asoc = temp; - } + /* Otherwise this is a UDP-style socket. */ + asoc = (struct sctp_association *)id; + if (!sctp_assoc_valid(sk, asoc)) + return NULL; return asoc; } +/* Look up the transport from an address and an assoc id. If both address and + * id are specified, the associations matching the address and the id should be + * the same. + */ +struct sctp_transport *sctp_addr_id2transport(struct sock *sk, + struct sockaddr_storage *addr, + sctp_assoc_t id) +{ + struct sctp_association *addr_asoc = NULL, *id_asoc = NULL; + struct sctp_transport *transport; + union sctp_addr *laddr = (union sctp_addr *)addr; + + laddr->v4.sin_port = ntohs(laddr->v4.sin_port); + addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep, + (union sctp_addr *)addr, + &transport); + laddr->v4.sin_port = htons(laddr->v4.sin_port); + + if (!addr_asoc) + return NULL; + + id_asoc = sctp_id2assoc(sk, id); + if (id_asoc && (id_asoc != addr_asoc)) + return NULL; + + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)addr); + + return transport; +} + /* API 3.1.2 bind() - UDP Style Syntax * The syntax of bind() is, * @@ -139,10 +181,7 @@ * sd - the socket descriptor returned by socket(). * addr - the address structure (struct sockaddr_in or struct * sockaddr_in6 [RFC 2553]), - * addrlen - the size of the address structure. - * - * The caller should use struct sockaddr_storage described in RFC 2553 - * to represent addr for portability reason. + * addr_len - the size of the address structure. */ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -178,7 +217,7 @@ return NULL; /* Does this PF support this AF? */ - if (!opt->pf->af_supported(addr->sa.sa_family)) + if (!opt->pf->af_supported(addr->sa.sa_family, opt)) return NULL; /* If we get this far, af is valid. */ @@ -195,7 +234,7 @@ { struct sctp_opt *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_bind_addr *bp = &ep->base.bind_addr; struct sctp_af *af; unsigned short snum; int ret = 0; @@ -243,7 +282,7 @@ /* Refresh ephemeral port. */ if (!snum) - snum = (sk)->num; + snum = sk->num; /* Add the address to the bind address list. */ sctp_local_bh_disable(); @@ -260,116 +299,45 @@ /* Copy back into socket for getsockname() use. */ if (!ret) { - (sk)->sport = htons((sk)->num); + sk->sport = htons(sk->num); af->to_sk_saddr(addr, sk); } return ret; } -/* API 8.1 sctp_bindx() - * - * The syntax of sctp_bindx() is, - * - * ret = sctp_bindx(int sd, - * struct sockaddr_storage *addrs, - * int addrcnt, - * int flags); - * - * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. - * If the sd is an IPv6 socket, the addresses passed can either be IPv4 - * or IPv6 addresses. - * - * A single address may be specified as INADDR_ANY or IPV6_ADDR_ANY, see - * section 3.1.2 for this usage. - * - * addrs is a pointer to an array of one or more socket addresses. Each - * address is contained in a struct sockaddr_storage, so each address is - * fixed length. The caller specifies the number of addresses in the - * array with addrcnt. - * - * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns -1, - * and sets errno to the appropriate error code. [ Editor's note: need - * to fill in all error code? ] - * - * For SCTP, the port given in each socket address must be the same, or - * sctp_bindx() will fail, setting errno to EINVAL . - * - * The flags parameter is formed from the bitwise OR of zero or - * more of the following currently defined flags: - * - * SCTP_BINDX_ADD_ADDR - * SCTP_BINDX_REM_ADDR - * - * SCTP_BIND_ADD_ADDR directs SCTP to add the given addresses to the - * association, and SCTP_BIND_REM_ADDR directs SCTP to remove the given - * addresses from the association. The two flags are mutually exclusive; - * if both are given, sctp_bindx() will fail with EINVAL. A caller may not - * remove all addresses from an association; sctp_bindx() will reject such - * an attempt with EINVAL. - * - * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate - * additional addresses with an endpoint after calling bind(). Or use - * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening - * socket is associated with so that no new association accepted will be - * associated with those addresses. - * - * SCTP_BIND_ADD_ADDR is defined as 0, so that it becomes the default - * behavior for sctp_bindx() when no flags are given. - * - * Adding and removing addresses from a connected association is optional - * functionality. Implementations that do not support this functionality - * should return EOPNOTSUPP. - * - * NOTE: This could be integrated into sctp_setsockopt_bindx(), - * but keeping it this way makes it easier if sometime sys_bindx is - * added. - */ - -/* Unprotected by locks. Call only with socket lock sk->lock held! See - * sctp_bindx() for a lock-protected call. - */ - -static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, - int addrcnt, int flags) -{ - int retval = 0; - - SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " - "flags: %s)\n", sk, addrs, addrcnt, - (BINDX_ADD_ADDR == flags) ? "ADD" : - ((BINDX_REM_ADDR == flags) ? "REM" : "BOGUS")); - - switch (flags) { - case BINDX_ADD_ADDR: - retval = sctp_bindx_add(sk, addrs, addrcnt); - break; - - case BINDX_REM_ADDR: - retval = sctp_bindx_rem(sk, addrs, addrcnt); - break; - - default: - retval = -EINVAL; - break; - }; - - return retval; -} - -/* BINDX with locks. + /* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks * - * NOTE: Currently unused at all ... - */ -int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, - int flags) -{ - int retval; - - sctp_lock_sock(sk); - retval = __sctp_bindx(sk, addrs, addrcnt, flags); - sctp_release_sock(sk); + * R1) One and only one ASCONF Chunk MAY be in transit and unacknowledged + * at any one time. If a sender, after sending an ASCONF chunk, decides + * it needs to transfer another ASCONF Chunk, it MUST wait until the + * ASCONF-ACK Chunk returns from the previous ASCONF Chunk before sending a + * subsequent ASCONF. Note this restriction binds each side, so at any + * time two ASCONF may be in-transit on any given association (one sent + * from each endpoint). + */ +static int sctp_send_asconf(struct sctp_association *asoc, + struct sctp_chunk *chunk) +{ + int retval = 0; + + /* If there is an outstanding ASCONF chunk, queue it for later + * transmission. + */ + if (asoc->addip_last_asconf) { + __skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk); + goto out; + } + + /* Hold the chunk until an ASCONF_ACK is received. */ + sctp_chunk_hold(chunk); + retval = sctp_primitive_ASCONF(asoc, chunk); + if (retval) + sctp_chunk_free(chunk); + else + asoc->addip_last_asconf = chunk; +out: return retval; } @@ -383,88 +351,147 @@ * If any of them fails, then the operation will be reversed and the * ones that were added will be removed. * - * Only __sctp_bindx() is supposed to call this function. + * Only sctp_setsockopt_bindx() is supposed to call this function. */ -int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt) { int cnt; int retval = 0; - int addr_len; + void *addr_buf; + struct sockaddr *sa_addr; + struct sctp_af *af; SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n", sk, addrs, addrcnt); + addr_buf = addrs; for (cnt = 0; cnt < addrcnt; cnt++) { /* The list may contain either IPv4 or IPv6 address; * determine the address length for walking thru the list. */ - switch (((struct sockaddr *)&addrs[cnt])->sa_family) { - case AF_INET: - addr_len = sizeof(struct sockaddr_in); - break; - - case AF_INET6: - addr_len = sizeof(struct sockaddr_in6); - break; - - default: + sa_addr = (struct sockaddr *)addr_buf; + af = sctp_get_af_specific(sa_addr->sa_family); + if (!af) { retval = -EINVAL; goto err_bindx_add; - }; + } - retval = sctp_do_bind(sk, (union sctp_addr *)&addrs[cnt], - addr_len); + retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr, + af->sockaddr_len); + + addr_buf += af->sockaddr_len; err_bindx_add: if (retval < 0) { - /* Failed. Cleanup the ones that has been added */ + /* Failed. Cleanup the ones that have been added */ if (cnt > 0) sctp_bindx_rem(sk, addrs, cnt); return retval; } } - /* Notify the peer(s), assuming we have (an) association(s). - * FIXME: for UDP, we have a 1-1-many mapping amongst sk, ep and asoc, - * so we don't have to do much work on locating associations. - * - * However, when the separation of ep and asoc kicks in, especially - * for TCP style connection, it becomes n-1-n mapping. We will need - * to do more fine work. Until then, hold my peace. - * --xguo - * - * Really, I don't think that will be a problem. The bind() - * call on a socket will either know the endpoint - * (e.g. TCP-style listen()ing socket, or UDP-style socket), - * or exactly one association. The former case is EXACTLY - * what we have now. In the former case we know the - * association already. --piggy - * - * This code will be working on either a UDP style or a TCP style - * socket, or say either an endpoint or an association. The socket - * type verification code need to be added later before calling the - * ADDIP code. - * --daisy - */ + return retval; +} -#if CONFIG_IP_SCTP_ADDIP - /* Add these addresses to all associations on this endpoint. */ - if (retval >= 0) { - struct list_head *pos; - struct sctp_endpoint *ep; - struct sctp_association *asoc; - ep = sctp_sk(sk)->ep; +/* Send an ASCONF chunk with Add IP address parameters to all the peers of the + * associations that are part of the endpoint indicating that a list of local + * addresses are added to the endpoint. + * + * If any of the addresses is already in the bind address list of the + * association, we do not send the chunk for that association. But it will not + * affect other associations. + * + * Only sctp_setsockopt_bindx() is supposed to call this function. + */ +static int sctp_send_asconf_add_ip(struct sock *sk, + struct sockaddr *addrs, + int addrcnt) +{ + struct sctp_opt *sp; + struct sctp_endpoint *ep; + struct sctp_association *asoc; + struct sctp_bind_addr *bp; + struct sctp_chunk *chunk; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *addr; + void *addr_buf; + struct sctp_af *af; + struct list_head *pos; + struct list_head *p; + int i; + int retval = 0; + + if (!sctp_addip_enable) + return retval; + + sp = sctp_sk(sk); + ep = sp->ep; + + SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", + __FUNCTION__, sk, addrs, addrcnt); + + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, struct sctp_association, asocs); - list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, struct sctp_association, asocs); + if (!asoc->peer.asconf_capable) + continue; + + if (asoc->peer.addip_disabled_mask & SCTP_PARAM_ADD_IP) + continue; - sctp_addip_addr_config(asoc, - SCTP_PARAM_ADD_IP, - addrs, addrcnt); + if (!sctp_state(asoc, ESTABLISHED)) + continue; + + /* Check if any address in the packed array of addresses is + * in the bind address list of the association. If so, + * do not send the asconf chunk to its peer, but continue with + * other associations. + */ + addr_buf = addrs; + for (i = 0; i < addrcnt; i++) { + addr = (union sctp_addr *)addr_buf; + af = sctp_get_af_specific(addr->v4.sin_family); + if (!af) { + retval = -EINVAL; + goto out; + } + + if (sctp_assoc_lookup_laddr(asoc, addr)) + break; + + addr_buf += af->sockaddr_len; } + if (i < addrcnt) + continue; + + /* Use the first address in bind addr list of association as + * Address Parameter of ASCONF CHUNK. + */ + sctp_read_lock(&asoc->base.addr_lock); + bp = &asoc->base.bind_addr; + p = bp->address_list.next; + laddr = list_entry(p, struct sctp_sockaddr_entry, list); + sctp_read_unlock(&asoc->base.addr_lock); + + chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, + addrcnt, SCTP_PARAM_ADD_IP); + if (!chunk) { + retval = -ENOMEM; + goto out; + } + + retval = sctp_send_asconf(asoc, chunk); + + /* FIXME: After sending the add address ASCONF chunk, we + * cannot append the address to the association's binding + * address list, because the new address may be used as the + * source of a message sent to the peer before the ASCONF + * chunk is received by the peer. So we should wait until + * ASCONF_ACK is received. + */ } -#endif +out: return retval; } @@ -481,63 +508,54 @@ * At least one address has to be left; if only one address is * available, the operation will return -EBUSY. * - * Only __sctp_bindx() is supposed to call this function. + * Only sctp_setsockopt_bindx() is supposed to call this function. */ -int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) +int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) { struct sctp_opt *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; int cnt; - sctp_bind_addr_t *bp = &ep->base.bind_addr; + struct sctp_bind_addr *bp = &ep->base.bind_addr; int retval = 0; union sctp_addr saveaddr; + void *addr_buf; + struct sockaddr *sa_addr; + struct sctp_af *af; SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n", sk, addrs, addrcnt); + addr_buf = addrs; for (cnt = 0; cnt < addrcnt; cnt++) { - /* If there is only one bind address, there is nothing more - * to be removed (we need at least one address here). + /* If the bind address list is empty or if there is only one + * bind address, there is nothing more to be removed (we need + * at least one address here). */ - if (list_empty(&bp->address_list)) { + if (list_empty(&bp->address_list) || + (sctp_list_single_entry(&bp->address_list))) { retval = -EBUSY; goto err_bindx_rem; } /* The list may contain either IPv4 or IPv6 address; - * determine the address length for walking thru the list. + * determine the address length to copy the address to + * saveaddr. */ - switch (((struct sockaddr *)&addrs[cnt])->sa_family) { - case AF_INET: - saveaddr = *((union sctp_addr *) - &addrs[cnt]); - saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port); - /* Verify the port. */ - if (saveaddr.v4.sin_port != bp->port) { - retval = -EINVAL; - goto err_bindx_rem; - } - break; - - case AF_INET6: - saveaddr = *((union sctp_addr *) - &addrs[cnt]); - saveaddr.v6.sin6_port = - ntohs(saveaddr.v6.sin6_port); - /* verify the port */ - if (saveaddr.v6.sin6_port != bp->port) { - retval = -EINVAL; - goto err_bindx_rem; - } - break; - - default: + sa_addr = (struct sockaddr *)addr_buf; + af = sctp_get_af_specific(sa_addr->sa_family); + if (!af) { retval = -EINVAL; goto err_bindx_rem; - }; + } + memcpy(&saveaddr, sa_addr, af->sockaddr_len); + saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port); + if (saveaddr.v4.sin_port != bp->port) { + retval = -EINVAL; + goto err_bindx_rem; + } - /* FIXME - There is probably a need to check if sk->saddr and - * sk->rcv_addr are currently set to one of the addresses to + /* FIXME - There is probably a need to check if sk->sk_saddr and + * sk->sk_rcv_addr are currently set to one of the addresses to * be removed. This is something which needs to be looked into * when we are fixing the outstanding issues with multi-homing * socket routing and failover schemes. Refer to comments in @@ -551,6 +569,7 @@ sctp_write_unlock(&ep->base.addr_lock); sctp_local_bh_enable(); + addr_buf += af->sockaddr_len; err_bindx_rem: if (retval < 0) { /* Failed. Add the ones that has been removed back */ @@ -560,43 +579,167 @@ } } - /* - * This code will be working on either a UDP style or a TCP style - * socket, * or say either an endpoint or an association. The socket - * type verification code need to be added later before calling the - * ADDIP code. - * --daisy - */ -#if CONFIG_IP_SCTP_ADDIP - /* Remove these addresses from all associations on this endpoint. */ - if (retval >= 0) { - struct list_head *pos; - struct sctp_endpoint *ep; - struct sctp_association *asoc; + return retval; +} - ep = sctp_sk(sk)->ep; - list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, struct sctp_association, asocs); - sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP, - addrs, addrcnt); +/* Send an ASCONF chunk with Delete IP address parameters to all the peers of + * the associations that are part of the endpoint indicating that a list of + * local addresses are removed from the endpoint. + * + * If any of the addresses is already in the bind address list of the + * association, we do not send the chunk for that association. But it will not + * affect other associations. + * + * Only sctp_setsockopt_bindx() is supposed to call this function. + */ +static int sctp_send_asconf_del_ip(struct sock *sk, + struct sockaddr *addrs, + int addrcnt) +{ + struct sctp_opt *sp; + struct sctp_endpoint *ep; + struct sctp_association *asoc; + struct sctp_bind_addr *bp; + struct sctp_chunk *chunk; + union sctp_addr *laddr; + void *addr_buf; + struct sctp_af *af; + struct list_head *pos; + int i; + int retval = 0; + + if (!sctp_addip_enable) + return retval; + + sp = sctp_sk(sk); + ep = sp->ep; + + SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", + __FUNCTION__, sk, addrs, addrcnt); + + list_for_each(pos, &ep->asocs) { + asoc = list_entry(pos, struct sctp_association, asocs); + + if (!asoc->peer.asconf_capable) + continue; + + if (asoc->peer.addip_disabled_mask & SCTP_PARAM_DEL_IP) + continue; + + if (!sctp_state(asoc, ESTABLISHED)) + continue; + + /* Check if any address in the packed array of addresses is + * not present in the bind address list of the association. + * If so, do not send the asconf chunk to its peer, but + * continue with other associations. + */ + addr_buf = addrs; + for (i = 0; i < addrcnt; i++) { + laddr = (union sctp_addr *)addr_buf; + af = sctp_get_af_specific(laddr->v4.sin_family); + if (!af) { + retval = -EINVAL; + goto out; + } + + if (!sctp_assoc_lookup_laddr(asoc, laddr)) + break; + + addr_buf += af->sockaddr_len; } + if (i < addrcnt) + continue; + + /* Find one address in the association's bind address list + * that is not in the packed array of addresses. This is to + * make sure that we do not delete all the addresses in the + * association. + */ + sctp_read_lock(&asoc->base.addr_lock); + bp = &asoc->base.bind_addr; + laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, + addrcnt, sp); + sctp_read_unlock(&asoc->base.addr_lock); + if (!laddr) + continue; + + chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, + SCTP_PARAM_DEL_IP); + if (!chunk) { + retval = -ENOMEM; + goto out; + } + + retval = sctp_send_asconf(asoc, chunk); + + /* FIXME: After sending the delete address ASCONF chunk, we + * cannot remove the addresses from the association's bind + * address list, because there maybe some packet send to + * the delete addresses, so we should wait until ASCONF_ACK + * packet is received. + */ } -#endif +out: return retval; } -/* Helper for tunneling sys_bindx() requests through sctp_setsockopt() +/* Helper for tunneling sctp_bindx() requests through sctp_setsockopt() + * + * API 8.1 + * int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, + * int flags); + * + * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses. + * If the sd is an IPv6 socket, the addresses passed can either be IPv4 + * or IPv6 addresses. + * + * A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see + * Section 3.1.2 for this usage. + * + * addrs is a pointer to an array of one or more socket addresses. Each + * address is contained in its appropriate structure (i.e. struct + * sockaddr_in or struct sockaddr_in6) the family of the address type + * must be used to distengish the address length (note that this + * representation is termed a "packed array" of addresses). The caller + * specifies the number of addresses in the array with addrcnt. + * + * On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns + * -1, and sets errno to the appropriate error code. + * + * For SCTP, the port given in each socket address must be the same, or + * sctp_bindx() will fail, setting errno to EINVAL. + * + * The flags parameter is formed from the bitwise OR of zero or more of + * the following currently defined flags: + * + * SCTP_BINDX_ADD_ADDR + * + * SCTP_BINDX_REM_ADDR + * + * SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the + * association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given + * addresses from the association. The two flags are mutually exclusive; + * if both are given, sctp_bindx() will fail with EINVAL. A caller may + * not remove all addresses from an association; sctp_bindx() will + * reject such an attempt with EINVAL. + * + * An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate + * additional addresses with an endpoint after calling bind(). Or use + * sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening + * socket is associated with so that no new association accepted will be + * associated with those addresses. If the endpoint supports dynamic + * address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a + * endpoint to send the appropriate message to the peer to change the + * peers address lists. + * + * Adding and removing addresses from a connected association is + * optional functionality. Implementations that do not support this + * functionality should return EOPNOTSUPP. * * Basically do nothing but copying the addresses from user to kernel - * land and invoking sctp_bindx on the sk. This is used for tunneling - * the sctp_bindx() [sys_bindx()] request through sctp_setsockopt() - * from userspace. - * - * Note I don't use move_addr_to_kernel(): the reason is we would be - * iterating over an array of struct sockaddr_storage passing always - * what we know is a good size (sizeof (struct sock...)), so it is - * pointless. Instead check the whole area for read access and copy - * it. + * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk. + * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() * from userspace. * * We don't use copy_from_user() for optimization: we first do the * sanity checks (buffer size -fast- and access check-healthy @@ -616,38 +759,77 @@ * * Returns 0 if ok, <0 errno code on error. */ -SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, - struct sockaddr_storage *addrs, - int addrssize, int op) +SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs, + int addrs_size, int op) { - struct sockaddr_storage *kaddrs; + struct sockaddr *kaddrs; int err; - size_t addrcnt; + int addrcnt = 0; + int walk_size = 0; + struct sockaddr *sa_addr; + void *addr_buf; + struct sctp_af *af; - SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" - " addrssize %d opt %d\n", sk, addrs, addrssize, op); + SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p" + " addrs_size %d opt %d\n", sk, addrs, addrs_size, op); - /* Do we have an integer number of structs sockaddr_storage? */ - if (unlikely(addrssize <= 0 || - addrssize % sizeof(struct sockaddr_storage) != 0)) + if (unlikely(addrs_size <= 0)) return -EINVAL; /* Check the user passed a healthy pointer. */ - if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize))) + if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size))) return -EFAULT; /* Alloc space for the address array in kernel memory. */ - kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL); + kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL); if (unlikely(!kaddrs)) return -ENOMEM; - if (copy_from_user(kaddrs, addrs, addrssize)) { + if (__copy_from_user(kaddrs, addrs, addrs_size)) { kfree(kaddrs); return -EFAULT; } - addrcnt = addrssize / sizeof(struct sockaddr_storage); - err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */ + /* Walk through the addrs buffer and count the number of addresses. */ + addr_buf = kaddrs; + while (walk_size < addrs_size) { + sa_addr = (struct sockaddr *)addr_buf; + af = sctp_get_af_specific(sa_addr->sa_family); + + /* If the address family is not supported or if this address + * causes the address buffer to overflow return EINVAL. + */ + if (!af || (walk_size + af->sockaddr_len) > addrs_size) { + kfree(kaddrs); + return -EINVAL; + } + addrcnt++; + addr_buf += af->sockaddr_len; + walk_size += af->sockaddr_len; + } + + /* Do the work. */ + switch (op) { + case SCTP_BINDX_ADD_ADDR: + err = sctp_bindx_add(sk, kaddrs, addrcnt); + if (err) + goto out; + err = sctp_send_asconf_add_ip(sk, kaddrs, addrcnt); + break; + + case SCTP_BINDX_REM_ADDR: + err = sctp_bindx_rem(sk, kaddrs, addrcnt); + if (err) + goto out; + err = sctp_send_asconf_del_ip(sk, kaddrs, addrcnt); + break; + + default: + err = -EINVAL; + break; + }; + +out: kfree(kaddrs); return err; @@ -671,6 +853,37 @@ * * If sd in the close() call is a branched-off socket representing only * one association, the shutdown is performed on that association only. + * + * 4.1.6 close() - TCP Style Syntax + * + * Applications use close() to gracefully close down an association. + * + * The syntax is: + * + * int close(int sd); + * + * sd - the socket descriptor of the association to be closed. + * + * After an application calls close() on a socket descriptor, no further + * socket operations will succeed on that descriptor. + * + * API 7.1.4 SO_LINGER + * + * An application using the TCP-style socket can use this option to + * perform the SCTP ABORT primitive. The linger option structure is: + * + * struct linger { + * int l_onoff; // option on/off + * int l_linger; // linger time + * }; + * + * To enable the option, set l_onoff to 1. If the l_linger value is set + * to 0, calling close() is the same as the ABORT primitive. If the + * value is set to a negative value, the setsockopt() call will return + * an error. If the value is set to a positive value linger_time, the + * close() can be blocked for at most linger_time ms. If the graceful + * shutdown phase does not finish during this period, close() will + * return but the graceful shutdown phase continues in the system. */ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) { @@ -678,10 +891,10 @@ struct sctp_association *asoc; struct list_head *pos, *temp; - SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk); + SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); sctp_lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; ep = sctp_sk(sk)->ep; @@ -689,21 +902,31 @@ list_for_each_safe(pos, temp, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); - /* A closed association can still be in the list if it - * belongs to a TCP-style listening socket that is not - * yet accepted. - */ - if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) && - (SCTP_STATE_CLOSED == asoc->state)) { - sctp_unhash_established(asoc); - sctp_association_free(asoc); + if (sctp_style(sk, TCP)) { + /* A closed association can still be in the list if + * it belongs to a TCP-style listening socket that is + * not yet accepted. If so, free it. If not, send an + * ABORT or SHUTDOWN based on the linger options. + */ + if (sctp_state(asoc, CLOSED)) { + sctp_unhash_established(asoc); + sctp_association_free(asoc); + + } else if (sk->linger && !sk->sk_lingertime) + sctp_primitive_ABORT(asoc, NULL); + else + sctp_primitive_SHUTDOWN(asoc, NULL); } else sctp_primitive_SHUTDOWN(asoc, NULL); } /* Clean up any skbs sitting on the receive queue. */ - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sctp_sk(sk)->pd_lobby); + sctp_queue_purge_ulpevents(&sk->sk_receive_queue); + sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); + + /* On a TCP-style socket, block for at most linger_time if set. */ + if (sctp_style(sk, TCP) && timeout) + sctp_wait_for_close(sk, timeout); /* This will run the backlog queue. */ sctp_release_sock(sk); @@ -768,8 +991,8 @@ struct sctp_opt *sp; struct sctp_endpoint *ep; struct sctp_association *new_asoc=NULL, *asoc=NULL; - struct sctp_transport *transport; - sctp_chunk_t *chunk = NULL; + struct sctp_transport *transport, *chunk_tp; + struct sctp_chunk *chunk; union sctp_addr to; struct sockaddr *msg_name = NULL; struct sctp_sndrcvinfo default_sinfo = { 0 }; @@ -781,10 +1004,11 @@ sctp_scope_t scope; long timeo; __u16 sinfo_flags = 0; - struct sk_buff_head chunks; + struct sctp_datamsg *datamsg; + struct list_head *pos; int msg_flags = msg->msg_flags; - SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", + SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %u)\n", sk, msg, msg_len); err = 0; @@ -793,8 +1017,8 @@ SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name); - if ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_ESTABLISHED != sk->state)) { + /* We cannot send a message over a TCP-style listening socket. */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) { err = -EPIPE; goto out_nounlock; } @@ -812,7 +1036,7 @@ * the address we will send to. * For a peeled-off socket, msg_name is ignored. */ - if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { + if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) { int msg_namelen = msg->msg_namelen; err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name, @@ -840,9 +1064,15 @@ associd = sinfo->sinfo_assoc_id; } - SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n", + SCTP_DEBUG_PRINTK("msg_len: %u, sinfo_flags: 0x%x\n", msg_len, sinfo_flags); + /* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */ + if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) { + err = -EINVAL; + goto out_nounlock; + } + /* If MSG_EOF is set, no data can be sent. Disallow sending zero * length messages when MSG_EOF|MSG_ABORT is not set. * If MSG_ABORT is set, the message length could be non zero with @@ -854,22 +1084,33 @@ goto out_nounlock; } - sctp_lock_sock(sk); + /* If MSG_ADDR_OVER is set, there must be an address + * specified in msg_name. + */ + if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) { + err = -EINVAL; + goto out_nounlock; + } transport = NULL; SCTP_DEBUG_PRINTK("About to look up association.\n"); + sctp_lock_sock(sk); + /* If a msg_name has been specified, assume this is to be used. */ if (msg_name) { /* Look for a matching association on the endpoint. */ asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); if (!asoc) { /* If we could not find a matching association on the - * endpoint, make sure that there is no peeled-off - * association on another socket. + * endpoint, make sure that it is not a TCP-style + * socket that already has an association or there is + * no peeled-off association on another socket. */ - if (sctp_endpoint_is_peeled_off(ep, &to)) { + if ((sctp_style(sk, TCP) && + sctp_sstate(sk, ESTABLISHED)) || + sctp_endpoint_is_peeled_off(ep, &to)) { err = -EADDRNOTAVAIL; goto out_unlock; } @@ -877,22 +1118,20 @@ } else { asoc = sctp_id2assoc(sk, associd); if (!asoc) { - err = -EINVAL; + err = -EPIPE; goto out_unlock; } } if (asoc) { - SCTP_DEBUG_PRINTK("Just looked up association: " - "%s. \n", asoc->debug_name); + SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc); - /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED + /* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED * socket that has an association in CLOSED state. This can * happen when an accepted socket has an association that is - * already CLOSED. + * already CLOSED. */ - if ((SCTP_STATE_CLOSED == asoc->state) && - (SCTP_SOCKET_TCP == sp->type)) { + if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) { err = -EPIPE; goto out_unlock; } @@ -976,8 +1215,8 @@ = sinit->sinit_max_attempts; } if (sinit->sinit_max_init_timeo) { - asoc->max_init_timeo - = sinit->sinit_max_init_timeo * HZ; + asoc->max_init_timeo = + SCTP_MSECS_TO_JIFFIES(sinit->sinit_max_init_timeo); } } @@ -1001,11 +1240,11 @@ /* If the user didn't specify SNDRCVINFO, make up one with * some defaults. */ - default_sinfo.sinfo_stream = asoc->defaults.stream; - default_sinfo.sinfo_flags = asoc->defaults.flags; - default_sinfo.sinfo_ppid = asoc->defaults.ppid; - default_sinfo.sinfo_context = asoc->defaults.context; - default_sinfo.sinfo_timetolive = asoc->defaults.timetolive; + default_sinfo.sinfo_stream = asoc->default_stream; + default_sinfo.sinfo_flags = asoc->default_flags; + default_sinfo.sinfo_ppid = asoc->default_ppid; + default_sinfo.sinfo_context = asoc->default_context; + default_sinfo.sinfo_timetolive = asoc->default_timetolive; default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); sinfo = &default_sinfo; } @@ -1013,7 +1252,7 @@ /* API 7.1.7, the sndbuf size per association bounds the * maximum size of data that can be sent in a single send call. */ - if (msg_len > sk->sndbuf) { + if (msg_len > sk->sk_sndbuf) { err = -EMSGSIZE; goto out_free; } @@ -1043,64 +1282,71 @@ goto out_free; } - /* Break the message into multiple chunks of maximum size. */ - skb_queue_head_init(&chunks); - err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks); - if (err) - goto out_free; + /* If an address is passed with the sendto/sendmsg call, it is used + * to override the primary destination address in the TCP model, or + * when MSG_ADDR_OVER flag is set in the UDP model. + */ + if ((sctp_style(sk, TCP) && msg_name) || + (sinfo_flags & MSG_ADDR_OVER)) { + chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); + if (!chunk_tp) { + err = -EINVAL; + goto out_free; + } + } else + chunk_tp = NULL; /* Auto-connect, if we aren't connected already. */ - if (SCTP_STATE_CLOSED == asoc->state) { + if (sctp_state(asoc, CLOSED)) { err = sctp_primitive_ASSOCIATE(asoc, NULL); if (err < 0) goto out_free; SCTP_DEBUG_PRINTK("We associated primitively.\n"); } + /* Break the message into multiple chunks of maximum size. */ + datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len); + if (!datamsg) { + err = -ENOMEM; + goto out_free; + } + /* Now send the (possibly) fragmented message. */ - while ((chunk = (sctp_chunk_t *)__skb_dequeue(&chunks))) { + list_for_each(pos, &datamsg->chunks) { + chunk = list_entry(pos, struct sctp_chunk, frag_list); + sctp_datamsg_track(chunk); /* Do accounting for the write space. */ sctp_set_owner_w(chunk); - /* This flag, in the UDP model, requests the SCTP stack to - * override the primary destination address with the - * address found with the sendto/sendmsg call. - */ - if (sinfo_flags & MSG_ADDR_OVER) { - if (!msg->msg_name) { - err = -EINVAL; - goto out_free; - } - chunk->transport = sctp_assoc_lookup_paddr(asoc, &to); - if (!chunk->transport) { - err = -EINVAL; - goto out_free; - } - } + chunk->transport = chunk_tp; - /* Send it to the lower layers. */ - sctp_primitive_SEND(asoc, chunk); + /* Send it to the lower layers. Note: all chunks + * must either fail or succeed. The lower layer + * works that way today. Keep it that way or this + * breaks. + */ + err = sctp_primitive_SEND(asoc, chunk); + /* Did the lower layer accept the chunk? */ + if (err) + sctp_chunk_free(chunk); SCTP_DEBUG_PRINTK("We sent primitively.\n"); } - if (!err) { + sctp_datamsg_free(datamsg); + if (err) + goto out_free; + else err = msg_len; - goto out_unlock; - } + /* If we are already past ASSOCIATE, the lower * layers are responsible for association cleanup. */ - goto out_free_chunk; + goto out_unlock; out_free: if (new_asoc) sctp_association_free(asoc); - -out_free_chunk: - if (chunk) - sctp_free_chunk(chunk); - out_unlock: sctp_release_sock(sk); @@ -1190,8 +1436,7 @@ sctp_lock_sock(sk); - if ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_ESTABLISHED != sk->state)) { + if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { err = -ENOTCONN; goto out; } @@ -1229,7 +1474,7 @@ sctp_ulpevent_read_sndrcvinfo(event, msg); #if 0 /* FIXME: we should be calling IP/IPv6 layers. */ - if (sk->protinfo.af_inet.cmsg_flags) + if (sk->sk_protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); #endif @@ -1244,14 +1489,14 @@ if (flags & MSG_PEEK) goto out_free; sctp_skb_pull(skb, copied); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); /* When only partial message is copied to the user, increase * rwnd by that amount. If all the data in the skb is read, - * rwnd is updated when the skb's destructor is called via - * sctp_ulpevent_free(). + * rwnd is updated when the event is freed. */ - sctp_assoc_rwnd_increase(event->event_asoc, copied); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) @@ -1260,12 +1505,30 @@ msg->msg_flags &= ~MSG_EOR; out_free: - sctp_ulpevent_free(event); /* Free the skb. */ + if (flags & MSG_PEEK) { + /* Release the skb reference acquired after peeking the skb in + * sctp_skb_recv_datagram(). + */ + kfree_skb(skb); + } else { + /* Free the event which includes releasing the reference to + * the owner of the skb, freeing the skb and updating the + * rwnd. + */ + sctp_ulpevent_free(event); + } out: sctp_release_sock(sk); return err; } +/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) + * + * This option is a on/off flag. If enabled no SCTP message + * fragmentation will be performed. Instead if a message being sent + * exceeds the current PMTU size, the message will NOT be sent and + * instead a error will be indicated to the user. + */ static int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) { @@ -1292,13 +1555,24 @@ return 0; } +/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) + * + * This socket option is applicable to the UDP-style socket only. When + * set it will cause associations that are idle for more than the + * specified number of seconds to automatically close. An association + * being idle is defined an association that has NOT sent or received + * user data. The special value of '0' indicates that no automatic + * close of any associations should be performed. The option expects an + * integer defining the number of seconds of idle time before an + * association is closed. + */ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) { struct sctp_opt *sp = sctp_sk(sk); /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sp->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (optlen != sizeof(int)) return -EINVAL; @@ -1309,12 +1583,41 @@ return 0; } +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address of + * an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + * + * struct sctp_paddrparams { + * sctp_assoc_t spp_assoc_id; + * struct sockaddr_storage spp_address; + * uint32_t spp_hbinterval; + * uint16_t spp_pathmaxrxt; + * }; + * + * spp_assoc_id - (UDP style socket) This is filled in the application, + * and identifies the association for this query. + * spp_address - This specifies which address is of interest. + * spp_hbinterval - This contains the value of the heartbeat interval, + * in milliseconds. A value of 0, when modifying the + * parameter, specifies that the heartbeat on this + * address should be disabled. A value of UINT32_MAX + * (4294967295), when modifying the parameter, + * specifies that a heartbeat should be sent + * immediately to the peer address, and the current + * interval should remain unchanged. + * spp_pathmaxrxt - This contains the maximum number of + * retransmissions before this address shall be + * considered unreachable. + */ static int sctp_setsockopt_peer_addr_params(struct sock *sk, char *optval, int optlen) { struct sctp_paddrparams params; - struct sctp_association *asoc; - union sctp_addr *addr; struct sctp_transport *trans; int error; @@ -1323,15 +1626,10 @@ if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; - asoc = sctp_id2assoc(sk, params.spp_assoc_id); - if (!asoc) - return -EINVAL; - - addr = (union sctp_addr *) &(params.spp_address); - - trans = sctp_assoc_lookup_paddr(asoc, addr); + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, + params.spp_assoc_id); if (!trans) - return -ENOENT; + return -EINVAL; /* Applications can enable or disable heartbeats for any peer address * of an association, modify an address's heartbeat interval, force a @@ -1345,7 +1643,7 @@ * and the current interval should remain unchanged. */ if (0xffffffff == params.spp_hbinterval) { - error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans); + error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans); if (error) return error; } else { @@ -1355,7 +1653,8 @@ */ if (params.spp_hbinterval) { trans->hb_allowed = 1; - trans->hb_interval = params.spp_hbinterval * HZ / 1000; + trans->hb_interval = + SCTP_MSECS_TO_JIFFIES(params.spp_hbinterval); } else trans->hb_allowed = 0; } @@ -1368,17 +1667,41 @@ return 0; } +/* 7.1.3 Initialization Parameters (SCTP_INITMSG) + * + * Applications can specify protocol parameters for the default association + * initialization. The option name argument to setsockopt() and getsockopt() + * is SCTP_INITMSG. + * + * Setting initialization parameters is effective only on an unconnected + * socket (for UDP-style sockets only future associations are effected + * by the change). With TCP-style sockets, this option is inherited by + * sockets derived from a listener socket. + */ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) { + struct sctp_initmsg sinit; + struct sctp_opt *sp = sctp_sk(sk); + if (optlen != sizeof(struct sctp_initmsg)) return -EINVAL; - if (copy_from_user(&sctp_sk(sk)->initmsg, optval, optlen)) + if (copy_from_user(&sinit, optval, optlen)) return -EFAULT; + + if (sinit.sinit_num_ostreams) + sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams; + if (sinit.sinit_max_instreams) + sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams; + if (sinit.sinit_max_attempts) + sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts; + if (sinit.sinit_max_init_timeo) + sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo; + return 0; } /* - * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) + * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) * * Applications that wish to use the sendto() system call may wish to * specify a default set of parameters that would normally be supplied @@ -1396,6 +1719,7 @@ { struct sctp_sndrcvinfo info; struct sctp_association *asoc; + struct sctp_opt *sp = sctp_sk(sk); if (optlen != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -1403,54 +1727,54 @@ return -EFAULT; asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); - if (!asoc) + if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - asoc->defaults.stream = info.sinfo_stream; - asoc->defaults.flags = info.sinfo_flags; - asoc->defaults.ppid = info.sinfo_ppid; - asoc->defaults.context = info.sinfo_context; - asoc->defaults.timetolive = info.sinfo_timetolive; + if (asoc) { + asoc->default_stream = info.sinfo_stream; + asoc->default_flags = info.sinfo_flags; + asoc->default_ppid = info.sinfo_ppid; + asoc->default_context = info.sinfo_context; + asoc->default_timetolive = info.sinfo_timetolive; + } else { + sp->default_stream = info.sinfo_stream; + sp->default_flags = info.sinfo_flags; + sp->default_ppid = info.sinfo_ppid; + sp->default_context = info.sinfo_context; + sp->default_timetolive = info.sinfo_timetolive; + } + return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. */ -static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) +static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval, + int optlen) { - struct sctp_setpeerprim prim; - struct sctp_association *asoc; - union sctp_addr *addr; + struct sctp_prim prim; struct sctp_transport *trans; - if (optlen != sizeof(struct sctp_setpeerprim)) + if (optlen != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); - if (!asoc) - return -EINVAL; - - /* Find the requested address. */ - addr = (union sctp_addr *) &(prim.sspp_addr); - - trans = sctp_assoc_lookup_paddr(asoc, addr); + trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); if (!trans) - return -ENOENT; + return -EINVAL; - sctp_assoc_set_primary(asoc, trans); + sctp_assoc_set_primary(trans->asoc, trans); return 0; } /* - * * 7.1.5 SCTP_NODELAY * * Turn on/off any Nagle-like algorithm. This means that packets are @@ -1461,17 +1785,235 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, int optlen) { - __u8 val; + int val; - if (optlen < sizeof(__u8)) + if (optlen < sizeof(int)) return -EINVAL; - if (get_user(val, (__u8 *)optval)) + if (get_user(val, (int *)optval)) return -EFAULT; sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; return 0; } +/* + * + * 7.1.1 SCTP_RTOINFO + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access + * and modify these parameters. + * All parameters are time values, in milliseconds. A value of 0, when + * modifying the parameters, indicates that the current value should not + * be changed. + * + */ +static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { + struct sctp_rtoinfo rtoinfo; + struct sctp_association *asoc; + + if (optlen != sizeof (struct sctp_rtoinfo)) + return -EINVAL; + + if (copy_from_user(&rtoinfo, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); + + /* Set the values to the specific association */ + if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) { + if (rtoinfo.srto_initial != 0) + asoc->rto_initial = + SCTP_MSECS_TO_JIFFIES(rtoinfo.srto_initial); + if (rtoinfo.srto_max != 0) + asoc->rto_max = SCTP_MSECS_TO_JIFFIES(rtoinfo.srto_max); + if (rtoinfo.srto_min != 0) + asoc->rto_min = SCTP_MSECS_TO_JIFFIES(rtoinfo.srto_min); + } else { + /* If there is no association or the association-id = 0 + * set the values to the endpoint. + */ + struct sctp_opt *sp = sctp_sk(sk); + + if (rtoinfo.srto_initial != 0) + sp->rtoinfo.srto_initial = rtoinfo.srto_initial; + if (rtoinfo.srto_max != 0) + sp->rtoinfo.srto_max = rtoinfo.srto_max; + if (rtoinfo.srto_min != 0) + sp->rtoinfo.srto_min = rtoinfo.srto_min; + } + + return 0; +} + +/* + * + * 7.1.2 SCTP_ASSOCINFO + * + * This option is used to tune the the maximum retransmission attempts + * of the association. + * Returns an error if the new association retransmission value is + * greater than the sum of the retransmission value of the peer. + * See [SCTP] for more information. + * + */ +static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) +{ + + struct sctp_assocparams assocparams; + struct sctp_association *asoc; + + if (optlen != sizeof(struct sctp_assocparams)) + return -EINVAL; + if (copy_from_user(&assocparams, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); + + if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + /* Set the values to the specific association */ + if (asoc) { + if (assocparams.sasoc_asocmaxrxt != 0) + asoc->max_retrans = assocparams.sasoc_asocmaxrxt; + if (assocparams.sasoc_cookie_life != 0) { + asoc->cookie_life.tv_sec = + assocparams.sasoc_cookie_life / 1000; + asoc->cookie_life.tv_usec = + (assocparams.sasoc_cookie_life % 1000) + * 1000; + } + } else { + /* Set the values to the endpoint */ + struct sctp_opt *sp = sctp_sk(sk); + + if (assocparams.sasoc_asocmaxrxt != 0) + sp->assocparams.sasoc_asocmaxrxt = + assocparams.sasoc_asocmaxrxt; + if (assocparams.sasoc_cookie_life != 0) + sp->assocparams.sasoc_cookie_life = + assocparams.sasoc_cookie_life; + } + return 0; +} + +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) +{ + int val; + struct sctp_opt *sp = sctp_sk(sk); + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + if (val) + sp->v4mapped = 1; + else + sp->v4mapped = 0; + + return 0; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen) +{ + int val; + + if (optlen < sizeof(int)) + return -EINVAL; + if (get_user(val, (int *)optval)) + return -EFAULT; + if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) + return -EINVAL; + sctp_sk(sk)->user_frag = val; + + return 0; +} + + +/* + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ +static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval, + int optlen) +{ + struct sctp_opt *sp; + struct sctp_endpoint *ep; + struct sctp_association *asoc = NULL; + struct sctp_setpeerprim prim; + struct sctp_chunk *chunk; + int err; + + sp = sctp_sk(sk); + ep = sp->ep; + + if (!sctp_addip_enable) + return -EPERM; + + if (optlen != sizeof(struct sctp_setpeerprim)) + return -EINVAL; + + if (copy_from_user(&prim, optval, optlen)) + return -EFAULT; + + asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); + if (!asoc) + return -EINVAL; + + if (!asoc->peer.asconf_capable) + return -EPERM; + + if (asoc->peer.addip_disabled_mask & SCTP_PARAM_SET_PRIMARY) + return -EPERM; + + if (!sctp_state(asoc, ESTABLISHED)) + return -ENOTCONN; + + if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) + return -EADDRNOTAVAIL; + + /* Create an ASCONF chunk with SET_PRIMARY parameter */ + chunk = sctp_make_asconf_set_prim(asoc, + (union sctp_addr *)&prim.sspp_addr); + if (!chunk) + return -ENOMEM; + + err = sctp_send_asconf(asoc, chunk); + + SCTP_DEBUG_PRINTK("We set peer primary addr primitively.\n"); + + return err; +} + + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -1495,7 +2037,6 @@ char *optval, int optlen) { int retval = 0; - char *tmp; SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", sk, optname); @@ -1512,41 +2053,26 @@ goto out_nounlock; } - sctp_lock_sock(sk); - - switch (optname) { - case SCTP_SOCKOPT_DEBUG_NAME: - /* BUG! we don't ever seem to free this memory. --jgrimm */ - if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { - retval = -ENOMEM; - goto out_unlock; - } - - if (copy_from_user(tmp, optval, optlen)) { - retval = -EFAULT; - goto out_unlock; - } - tmp[optlen] = '\000'; - sctp_sk(sk)->ep->debug_name = tmp; - break; + sctp_lock_sock(sk); + switch (optname) { case SCTP_SOCKOPT_BINDX_ADD: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) - optval, optlen, BINDX_ADD_ADDR); + retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval, + optlen, SCTP_BINDX_ADD_ADDR); break; case SCTP_SOCKOPT_BINDX_REM: /* 'optlen' is the size of the addresses buffer. */ - retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) - optval, optlen, BINDX_REM_ADDR); + retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval, + optlen, SCTP_BINDX_REM_ADDR); break; case SCTP_DISABLE_FRAGMENTS: retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); break; - case SCTP_SET_EVENTS: + case SCTP_EVENTS: retval = sctp_setsockopt_events(sk, optval, optlen); break; @@ -1554,33 +2080,43 @@ retval = sctp_setsockopt_autoclose(sk, optval, optlen); break; - case SCTP_SET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); break; case SCTP_INITMSG: retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; - - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; - + case SCTP_PRIMARY_ADDR: + retval = sctp_setsockopt_primary_addr(sk, optval, optlen); + break; case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_setsockopt_peer_prim(sk, optval, optlen); + retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen); break; - case SCTP_NODELAY: retval = sctp_setsockopt_nodelay(sk, optval, optlen); break; - + case SCTP_RTOINFO: + retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); + break; + case SCTP_ASSOCINFO: + retval = sctp_setsockopt_associnfo(sk, optval, optlen); + break; + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_setsockopt_mappedv4(sk, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_setsockopt_maxseg(sk, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; }; -out_unlock: sctp_release_sock(sk); out_nounlock: @@ -1629,9 +2165,8 @@ * is already connected. * It cannot be done even on a TCP-style listening socket. */ - if ((SCTP_SS_ESTABLISHED == sk->state) || - ((SCTP_SOCKET_TCP == sp->type) && - (SCTP_SS_LISTENING == sk->state))) { + if (sctp_sstate(sk, ESTABLISHED) || + (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { err = -EISCONN; goto out_unlock; } @@ -1700,11 +2235,11 @@ } /* Initialize sk's dport and daddr for getpeername() */ - (sk)->dport = htons(asoc->peer.port); + sk->dport = htons(asoc->peer.port); af = sctp_get_af_specific(to.sa.sa_family); - af->to_sk_daddr(&to, sk); + af->to_sk_daddr(&to, sk); - timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); + timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); out_unlock: @@ -1740,17 +2275,17 @@ sp = sctp_sk(sk); ep = sp->ep; - if (SCTP_SOCKET_TCP != sp->type) { + if (!sctp_style(sk, TCP)) { error = -EOPNOTSUPP; goto out; } - if (SCTP_SS_LISTENING != sk->state) { + if (!sctp_sstate(sk, LISTENING)) { error = -EINVAL; goto out; } - timeo = sock_rcvtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); + timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); error = sctp_wait_for_accept(sk, timeo); if (error) @@ -1791,17 +2326,14 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) { struct sctp_endpoint *ep; - struct sctp_protocol *proto; struct sctp_opt *sp; SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); - proto = sctp_get_protocol(); - sp = sctp_sk(sk); /* Initialize the SCTP per socket area. */ - switch (sk->type) { + switch (sk->sk_type) { case SOCK_SEQPACKET: sp->type = SCTP_SOCKET_UDP; break; @@ -1812,45 +2344,51 @@ return -ESOCKTNOSUPPORT; } - /* FIXME: The next draft (04) of the SCTP Sockets Extensions - * should include a socket option for manipulating these - * message parameters (and a few others). + /* Initialize default send parameters. These parameters can be + * modified with the SCTP_DEFAULT_SEND_PARAM socket option. */ sp->default_stream = 0; sp->default_ppid = 0; + sp->default_flags = 0; + sp->default_context = 0; + sp->default_timetolive = 0; /* Initialize default setup parameters. These parameters * can be modified with the SCTP_INITMSG socket option or * overridden by the SCTP_INIT CMSG. */ - sp->initmsg.sinit_num_ostreams = proto->max_outstreams; - sp->initmsg.sinit_max_instreams = proto->max_instreams; - sp->initmsg.sinit_max_attempts = proto->max_retrans_init; - sp->initmsg.sinit_max_init_timeo = proto->rto_max / HZ; + sp->initmsg.sinit_num_ostreams = sctp_max_outstreams; + sp->initmsg.sinit_max_instreams = sctp_max_instreams; + sp->initmsg.sinit_max_attempts = sctp_max_retrans_init; + sp->initmsg.sinit_max_init_timeo = JIFFIES_TO_MSECS(sctp_rto_max); /* Initialize default RTO related parameters. These parameters can * be modified for with the SCTP_RTOINFO socket option. - * FIXME: These are not used yet. */ - sp->rtoinfo.srto_initial = proto->rto_initial; - sp->rtoinfo.srto_max = proto->rto_max; - sp->rtoinfo.srto_min = proto->rto_min; - - /* Initialize default event subscriptions. - * the struct sock is initialized to zero, so only - * enable the events needed. By default, UDP-style - * sockets enable io and association change notifications. - */ - if (SCTP_SOCKET_UDP == sp->type) { - sp->subscribe.sctp_data_io_event = 1; - sp->subscribe.sctp_association_event = 1; - } + sp->rtoinfo.srto_initial = JIFFIES_TO_MSECS(sctp_rto_initial); + sp->rtoinfo.srto_max = JIFFIES_TO_MSECS(sctp_rto_max); + sp->rtoinfo.srto_min = JIFFIES_TO_MSECS(sctp_rto_min); + + /* Initialize default association related parameters. These parameters + * can be modified with the SCTP_ASSOCINFO socket option. + */ + sp->assocparams.sasoc_asocmaxrxt = sctp_max_retrans_association; + sp->assocparams.sasoc_number_peer_destinations = 0; + sp->assocparams.sasoc_peer_rwnd = 0; + sp->assocparams.sasoc_local_rwnd = 0; + sp->assocparams.sasoc_cookie_life = + JIFFIES_TO_MSECS(sctp_valid_cookie_life); + + /* Initialize default event subscriptions. By default, all the + * options are off. + */ + memset(&sp->subscribe, 0, sizeof(struct sctp_event_subscribe)); /* Default Peer Address Parameters. These defaults can - * be modified via SCTP_SET_PEER_ADDR_PARAMS + * be modified via SCTP_PEER_ADDR_PARAMS */ - sp->paddrparam.spp_hbinterval = proto->hb_interval / HZ; - sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; + sp->paddrparam.spp_hbinterval = JIFFIES_TO_MSECS(sctp_hb_interval); + sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; /* If enabled no SCTP message fragmentation will be performed. * Configure through SCTP_DISABLE_FRAGMENTS socket option. @@ -1860,13 +2398,20 @@ /* Turn on/off any Nagle-like algorithm. */ sp->nodelay = 1; + /* Enable by default. */ + sp->v4mapped = 1; + /* Auto-close idle associations after the configured * number of seconds. A value of 0 disables this * feature. Configure through the SCTP_AUTOCLOSE socket option, * for UDP-style sockets only. */ sp->autoclose = 0; - sp->pf = sctp_get_pf_specific(sk->family); + + /* User specified fragmentation limit. */ + sp->user_frag = 0; + + sp->pf = sctp_get_pf_specific(sk->sk_family); /* Control variables for partial data delivery. */ sp->pd_mode = 0; @@ -1922,7 +2467,7 @@ struct sctp_endpoint *ep; struct sctp_association *asoc; - if (SCTP_SOCKET_TCP != sctp_sk(sk)->type) + if (!sctp_style(sk, TCP)) return; if (how & SEND_SHUTDOWN) { @@ -1974,17 +2519,25 @@ status.sstat_state = asoc->state; status.sstat_rwnd = asoc->peer.rwnd; status.sstat_unackdata = asoc->unack_data; - status.sstat_penddata = asoc->peer.tsn_map.pending_data; + + status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); status.sstat_instrms = asoc->c.sinit_max_instreams; status.sstat_outstrms = asoc->c.sinit_num_ostreams; + /* Just in time frag_point update. */ + if (sctp_sk(sk)->user_frag) + asoc->frag_point + = min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag); status.sstat_fragmentation_point = asoc->frag_point; status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(union sctp_addr)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)&status.sstat_primary.spinfo_address); status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; - status.sstat_primary.spinfo_rto = transport->rto; + status.sstat_primary.spinfo_rto = JIFFIES_TO_MSECS(transport->rto); status.sstat_primary.spinfo_mtu = transport->pmtu; if (put_user(len, optlen)) { @@ -2005,6 +2558,64 @@ return (retval); } + +/* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO) + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. + */ +static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len, + char *optval, int *optlen) +{ + struct sctp_paddrinfo pinfo; + struct sctp_transport *transport; + int retval = 0; + + if (len != sizeof(pinfo)) { + retval = -EINVAL; + goto out; + } + + if (copy_from_user(&pinfo, optval, sizeof(pinfo))) { + retval = -EFAULT; + goto out; + } + + transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address, + pinfo.spinfo_assoc_id); + if (!transport) + return -EINVAL; + + pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc); + pinfo.spinfo_state = transport->active; + pinfo.spinfo_cwnd = transport->cwnd; + pinfo.spinfo_srtt = transport->srtt; + pinfo.spinfo_rto = JIFFIES_TO_MSECS(transport->rto); + pinfo.spinfo_mtu = transport->pmtu; + + if (put_user(len, optlen)) { + retval = -EFAULT; + goto out; + } + + if (copy_to_user(optval, &pinfo, len)) { + retval = -EFAULT; + goto out; + } + +out: + return (retval); +} + +/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS) + * + * This option is a on/off flag. If enabled no SCTP message + * fragmentation will be performed. Instead if a message being sent + * exceeds the current PMTU size, the message will NOT be sent and + * instead a error will be indicated to the user. + */ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, char *optval, int *optlen) { @@ -2022,7 +2633,13 @@ return 0; } -static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +/* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) + * + * This socket option is used to specify various notifications and + * ancillary data the user wishes to receive. + */ +static int sctp_getsockopt_events(struct sock *sk, int len, char *optval, + int *optlen) { if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2031,10 +2648,21 @@ return 0; } +/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE) + * + * This socket option is applicable to the UDP-style socket only. When + * set it will cause associations that are idle for more than the + * specified number of seconds to automatically close. An association + * being idle is defined an association that has NOT sent or received + * user data. The special value of '0' indicates that no automatic + * close of any associations should be performed. The option expects an + * integer defining the number of seconds of idle time before an + * association is closed. + */ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) { /* Applicable to UDP-style socket only */ - if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) + if (sctp_style(sk, TCP)) return -EOPNOTSUPP; if (len != sizeof(int)) return -EINVAL; @@ -2054,11 +2682,11 @@ /* An association cannot be branched off from an already peeled-off * socket, nor is this supported for tcp style sockets. */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) + if (!sctp_style(sk, UDP)) return -EINVAL; /* Create a new socket. */ - err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); + err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (err < 0) return err; @@ -2114,12 +2742,41 @@ return retval; } +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address of + * an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + * + * struct sctp_paddrparams { + * sctp_assoc_t spp_assoc_id; + * struct sockaddr_storage spp_address; + * uint32_t spp_hbinterval; + * uint16_t spp_pathmaxrxt; + * }; + * + * spp_assoc_id - (UDP style socket) This is filled in the application, + * and identifies the association for this query. + * spp_address - This specifies which address is of interest. + * spp_hbinterval - This contains the value of the heartbeat interval, + * in milliseconds. A value of 0, when modifying the + * parameter, specifies that the heartbeat on this + * address should be disabled. A value of UINT32_MAX + * (4294967295), when modifying the parameter, + * specifies that a heartbeat should be sent + * immediately to the peer address, and the current + * interval should remain unchanged. + * spp_pathmaxrxt - This contains the maximum number of + * retransmissions before this address shall be + * considered unreachable. + */ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_paddrparams params; - struct sctp_association *asoc; - union sctp_addr *addr; struct sctp_transport *trans; if (len != sizeof(struct sctp_paddrparams)) @@ -2127,15 +2784,10 @@ if (copy_from_user(¶ms, optval, *optlen)) return -EFAULT; - asoc = sctp_id2assoc(sk, params.spp_assoc_id); - if (!asoc) - return -EINVAL; - - addr = (union sctp_addr *) &(params.spp_address); - - trans = sctp_assoc_lookup_paddr(asoc, addr); + trans = sctp_addr_id2transport(sk, ¶ms.spp_address, + params.spp_assoc_id); if (!trans) - return -ENOENT; + return -EINVAL; /* The value of the heartbeat interval, in milliseconds. A value of 0, * when modifying the parameter, specifies that the heartbeat on this @@ -2144,7 +2796,7 @@ if (!trans->hb_allowed) params.spp_hbinterval = 0; else - params.spp_hbinterval = trans->hb_interval * 1000 / HZ; + params.spp_hbinterval = JIFFIES_TO_MSECS(trans->hb_interval); /* spp_pathmaxrxt contains the maximum number of retransmissions * before this address shall be considered unreachable. @@ -2153,11 +2805,24 @@ if (copy_to_user(optval, ¶ms, len)) return -EFAULT; - *optlen = len; + + if (put_user(len, optlen)) + return -EFAULT; return 0; } +/* 7.1.3 Initialization Parameters (SCTP_INITMSG) + * + * Applications can specify protocol parameters for the default association + * initialization. The option name argument to setsockopt() and getsockopt() + * is SCTP_INITMSG. + * + * Setting initialization parameters is effective only on an unconnected + * socket (for UDP-style sockets only future associations are effected + * by the change). With TCP-style sockets, this option is inherited by + * sockets derived from a listener socket. + */ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) { if (len != sizeof(struct sctp_initmsg)) @@ -2168,7 +2833,7 @@ } static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, - char *optval, int *optlen) + char *optval, int *optlen) { sctp_assoc_t id; struct sctp_association *asoc; @@ -2181,9 +2846,7 @@ if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) return -EFAULT; - /* - * For UDP-style sockets, id specifies the association to query. - */ + /* For UDP-style sockets, id specifies the association to query. */ asoc = sctp_id2assoc(sk, id); if (!asoc) return -EINVAL; @@ -2191,21 +2854,22 @@ list_for_each(pos, &asoc->peer.transport_addr_list) { cnt ++; } - if (copy_to_user(optval, &cnt, sizeof(int))) - return -EFAULT; - return 0; + return cnt; } static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, - char *optval, int *optlen) + char *optval, int *optlen) { struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; struct sctp_transport *from; - struct sockaddr_storage *to; + void *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); + int addrlen; if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2214,19 +2878,22 @@ return -EFAULT; if (getaddrs.addr_num <= 0) return -EINVAL; - /* - * For UDP-style sockets, id specifies the association to query. - */ + + /* For UDP-style sockets, id specifies the association to query. */ asoc = sctp_id2assoc(sk, getaddrs.assoc_id); if (!asoc) return -EINVAL; - to = getaddrs.addrs; + to = (void *)getaddrs.addrs; list_for_each(pos, &asoc->peer.transport_addr_list) { from = list_entry(pos, struct sctp_transport, transports); - if (copy_to_user(to, &from->ipaddr, sizeof(from->ipaddr))) + memcpy(&temp, &from->ipaddr, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; + temp.v4.sin_port = htons(temp.v4.sin_port); + if (copy_to_user(to, &temp, addrlen)) return -EFAULT; - to ++; + to += addrlen ; cnt ++; if (cnt >= getaddrs.addr_num) break; } @@ -2241,7 +2908,7 @@ char *optval, int *optlen) { sctp_assoc_t id; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; struct sctp_association *asoc; struct list_head *pos; int cnt = 0; @@ -2270,22 +2937,23 @@ list_for_each(pos, &bp->address_list) { cnt ++; } - if (copy_to_user(optval, &cnt, sizeof(int))) - return -EFAULT; - return 0; + return cnt; } static int sctp_getsockopt_local_addrs(struct sock *sk, int len, char *optval, int *optlen) { - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; struct sctp_association *asoc; struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; - struct sockaddr_storage_list *from; - struct sockaddr_storage *to; + struct sctp_sockaddr_entry *from; + void *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); + int addrlen; if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2309,14 +2977,18 @@ bp = &asoc->base.bind_addr; } - to = getaddrs.addrs; + to = (void *)getaddrs.addrs; list_for_each(pos, &bp->address_list) { from = list_entry(pos, - struct sockaddr_storage_list, + struct sctp_sockaddr_entry, list); - if (copy_to_user(to, &from->a, sizeof(from->a))) + memcpy(&temp, &from->a, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; + temp.v4.sin_port = htons(temp.v4.sin_port); + if (copy_to_user(to, &temp, addrlen)) return -EFAULT; - to ++; + to += addrlen; cnt ++; if (cnt >= getaddrs.addr_num) break; } @@ -2327,35 +2999,43 @@ return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. */ -static int sctp_getsockopt_peer_prim(struct sock *sk, int len, - char *optval, int *optlen) +static int sctp_getsockopt_primary_addr(struct sock *sk, int len, + char *optval, int *optlen) { - struct sctp_setpeerprim prim; + struct sctp_prim prim; struct sctp_association *asoc; + struct sctp_opt *sp = sctp_sk(sk); - if (len != sizeof(struct sctp_setpeerprim)) + if (len != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); + asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); if (!asoc) return -EINVAL; if (!asoc->peer.primary_path) return -ENOTCONN; - - memcpy(&prim.sspp_addr, &asoc->peer.primary_path->ipaddr, + + asoc->peer.primary_path->ipaddr.v4.sin_port = + htons(asoc->peer.primary_path->ipaddr.v4.sin_port); + memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, sizeof(union sctp_addr)); + asoc->peer.primary_path->ipaddr.v4.sin_port = + ntohs(asoc->peer.primary_path->ipaddr.v4.sin_port); + + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, + (union sctp_addr *)&prim.ssp_addr); - if (copy_to_user(optval, &prim, sizeof(struct sctp_setpeerprim))) + if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) return -EFAULT; return 0; @@ -2363,12 +3043,14 @@ /* * - * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) + * 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM) * * Applications that wish to use the sendto() system call may wish to * specify a default set of parameters that would normally be supplied * through the inclusion of ancillary data. This socket option allows * such an application to set the default sctp_sndrcvinfo structure. + + * The application that wishes to use this socket option simply passes * in to this call the sctp_sndrcvinfo structure defined in Section * 5.2.2) The input parameters accepted by this call include @@ -2383,6 +3065,7 @@ { struct sctp_sndrcvinfo info; struct sctp_association *asoc; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_sndrcvinfo)) return -EINVAL; @@ -2390,14 +3073,22 @@ return -EFAULT; asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); - if (!asoc) + if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP)) return -EINVAL; - info.sinfo_stream = asoc->defaults.stream; - info.sinfo_flags = asoc->defaults.flags; - info.sinfo_ppid = asoc->defaults.ppid; - info.sinfo_context = asoc->defaults.context; - info.sinfo_timetolive = asoc->defaults.timetolive; + if (asoc) { + info.sinfo_stream = asoc->default_stream; + info.sinfo_flags = asoc->default_flags; + info.sinfo_ppid = asoc->default_ppid; + info.sinfo_context = asoc->default_context; + info.sinfo_timetolive = asoc->default_timetolive; + } else { + info.sinfo_stream = sp->default_stream; + info.sinfo_flags = sp->default_flags; + info.sinfo_ppid = sp->default_ppid; + info.sinfo_context = sp->default_context; + info.sinfo_timetolive = sp->default_timetolive; + } if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo))) return -EFAULT; @@ -2416,14 +3107,14 @@ */ static int sctp_getsockopt_nodelay(struct sock *sk, int len, - char *optval, int *optlen) + char *optval, int *optlen) { - __u8 val; + int val; - if (len < sizeof(__u8)) + if (len < sizeof(int)) return -EINVAL; - len = sizeof(__u8); + len = sizeof(int); val = (sctp_sk(sk)->nodelay == 1); if (put_user(len, optlen)) return -EFAULT; @@ -2432,6 +3123,185 @@ return 0; } +/* + * + * 7.1.1 SCTP_RTOINFO + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. sctp_rtoinfo structure is used to access + * and modify these parameters. + * All parameters are time values, in milliseconds. A value of 0, when + * modifying the parameters, indicates that the current value should not + * be changed. + * + */ +static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, + int *optlen) { + struct sctp_rtoinfo rtoinfo; + struct sctp_association *asoc; + + if (len != sizeof (struct sctp_rtoinfo)) + return -EINVAL; + + if (copy_from_user(&rtoinfo, optval, sizeof (struct sctp_rtoinfo))) + return -EFAULT; + + asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); + + if (!asoc && rtoinfo.srto_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + /* Values corresponding to the specific association. */ + if (asoc) { + rtoinfo.srto_initial = JIFFIES_TO_MSECS(asoc->rto_initial); + rtoinfo.srto_max = JIFFIES_TO_MSECS(asoc->rto_max); + rtoinfo.srto_min = JIFFIES_TO_MSECS(asoc->rto_min); + } else { + /* Values corresponding to the endpoint. */ + struct sctp_opt *sp = sctp_sk(sk); + + rtoinfo.srto_initial = sp->rtoinfo.srto_initial; + rtoinfo.srto_max = sp->rtoinfo.srto_max; + rtoinfo.srto_min = sp->rtoinfo.srto_min; + } + + if (put_user(len, optlen)) + return -EFAULT; + + if (copy_to_user(optval, &rtoinfo, len)) + return -EFAULT; + + return 0; +} + +/* + * + * 7.1.2 SCTP_ASSOCINFO + * + * This option is used to tune the the maximum retransmission attempts + * of the association. + * Returns an error if the new association retransmission value is + * greater than the sum of the retransmission value of the peer. + * See [SCTP] for more information. + * + */ +static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, + int *optlen) +{ + + struct sctp_assocparams assocparams; + struct sctp_association *asoc; + struct list_head *pos; + int cnt = 0; + + if (len != sizeof (struct sctp_assocparams)) + return -EINVAL; + + if (copy_from_user(&assocparams, optval, + sizeof (struct sctp_assocparams))) + return -EFAULT; + + asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); + + if (!asoc && assocparams.sasoc_assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + /* Values correspoinding to the specific association */ + if (assocparams.sasoc_assoc_id != 0) { + assocparams.sasoc_asocmaxrxt = asoc->max_retrans; + assocparams.sasoc_peer_rwnd = asoc->peer.rwnd; + assocparams.sasoc_local_rwnd = asoc->a_rwnd; + assocparams.sasoc_cookie_life = (asoc->cookie_life.tv_sec + * 1000) + + (asoc->cookie_life.tv_usec + / 1000); + + list_for_each(pos, &asoc->peer.transport_addr_list) { + cnt ++; + } + + assocparams.sasoc_number_peer_destinations = cnt; + } else { + /* Values corresponding to the endpoint */ + struct sctp_opt *sp = sctp_sk(sk); + + assocparams.sasoc_asocmaxrxt = sp->assocparams.sasoc_asocmaxrxt; + assocparams.sasoc_peer_rwnd = sp->assocparams.sasoc_peer_rwnd; + assocparams.sasoc_local_rwnd = sp->assocparams.sasoc_local_rwnd; + assocparams.sasoc_cookie_life = + sp->assocparams.sasoc_cookie_life; + assocparams.sasoc_number_peer_destinations = + sp->assocparams. + sasoc_number_peer_destinations; + } + + if (put_user(len, optlen)) + return -EFAULT; + + if (copy_to_user(optval, &assocparams, len)) + return -EFAULT; + + return 0; +} + +/* + * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR) + * + * This socket option is a boolean flag which turns on or off mapped V4 + * addresses. If this option is turned on and the socket is type + * PF_INET6, then IPv4 addresses will be mapped to V6 representation. + * If this option is turned off, then no mapping will be done of V4 + * addresses and a user will receive both PF_INET6 and PF_INET type + * addresses on the socket. + */ +static int sctp_getsockopt_mappedv4(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + struct sctp_opt *sp = sctp_sk(sk); + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + val = sp->v4mapped; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + +/* + * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) + * + * This socket option specifies the maximum size to put in any outgoing + * SCTP chunk. If a message is larger than this size it will be + * fragmented by SCTP into the specified size. Note that the underlying + * SCTP implementation may fragment into smaller sized chunks when the + * PMTU of the underlying association is smaller than the value set by + * the user. + */ +static int sctp_getsockopt_maxseg(struct sock *sk, int len, + char *optval, int *optlen) +{ + int val; + + if (len < sizeof(int)) + return -EINVAL; + + len = sizeof(int); + + val = sctp_sk(sk)->user_frag; + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { @@ -2466,8 +3336,8 @@ retval = sctp_getsockopt_disable_fragments(sk, len, optval, optlen); break; - case SCTP_SET_EVENTS: - retval = sctp_getsockopt_set_events(sk, len, optval, optlen); + case SCTP_EVENTS: + retval = sctp_getsockopt_events(sk, len, optval, optlen); break; case SCTP_AUTOCLOSE: retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); @@ -2475,7 +3345,7 @@ case SCTP_SOCKOPT_PEELOFF: retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; - case SCTP_GET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); break; @@ -2498,16 +3368,32 @@ retval = sctp_getsockopt_local_addrs(sk, len, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen); + case SCTP_PRIMARY_ADDR: + retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); break; case SCTP_NODELAY: retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); break; + case SCTP_RTOINFO: + retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); + break; + case SCTP_ASSOCINFO: + retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); + break; + case SCTP_I_WANT_MAPPED_V4_ADDR: + retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); + break; + case SCTP_MAXSEG: + retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); + break; + case SCTP_GET_PEER_ADDR_INFO: + retval = sctp_getsockopt_peer_addr_info(sk, len, optval, + optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -2531,7 +3417,7 @@ * * The port hash table (contained in the 'global' SCTP protocol storage * returned by struct sctp_protocol *sctp_get_protocol()). The hash - * table is an array of 4096 lists (sctp_bind_hashbucket_t). Each + * table is an array of 4096 lists (sctp_bind_hashbucket). Each * list (the list number is the port number hashed out, so as you * would expect from a hash function, all the ports in a given list have * such a number that hashes out to the same list number; you were @@ -2539,13 +3425,13 @@ * link to the socket (struct sock) that uses it, the port number and * a fastreuse flag (FIXME: NPI ipg). */ -static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, - unsigned short snum); +static struct sctp_bind_bucket *sctp_bucket_create( + struct sctp_bind_hashbucket *head, unsigned short snum); + static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) { - sctp_bind_hashbucket_t *head; /* hash list */ - sctp_bind_bucket_t *pp; /* hash list port iterator */ - struct sctp_protocol *sctp = sctp_get_protocol(); + struct sctp_bind_hashbucket *head; /* hash list */ + struct sctp_bind_bucket *pp; /* hash list port iterator */ unsigned short snum; int ret; @@ -2554,14 +3440,13 @@ snum = addr->v4.sin_port; SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); - sctp_local_bh_disable(); if (snum == 0) { /* Search for an available port. * - * 'sctp->port_rover' was the last port assigned, so - * we start to search from 'sctp->port_rover + + * 'sctp_port_rover' was the last port assigned, so + * we start to search from 'sctp_port_rover + * 1'. What we do is first check if port 'rover' is * already in the hash table; if not, we use that; if * it is, we try next. @@ -2572,14 +3457,14 @@ int rover; int index; - sctp_spin_lock(&sctp->port_alloc_lock); - rover = sctp->port_rover; + sctp_spin_lock(&sctp_port_alloc_lock); + rover = sctp_port_rover; do { rover++; if ((rover < low) || (rover > high)) rover = low; index = sctp_phashfn(rover); - head = &sctp->port_hashtable[index]; + head = &sctp_port_hashtable[index]; sctp_spin_lock(&head->lock); for (pp = head->chain; pp; pp = pp->next) if (pp->port == rover) @@ -2588,8 +3473,8 @@ next: sctp_spin_unlock(&head->lock); } while (--remaining > 0); - sctp->port_rover = rover; - sctp_spin_unlock(&sctp->port_alloc_lock); + sctp_port_rover = rover; + sctp_spin_unlock(&sctp_port_alloc_lock); /* Exhausted local port range during search? */ ret = 1; @@ -2609,7 +3494,7 @@ * to the port number (snum) - we detect that with the * port iterator, pp being NULL. */ - head = &sctp->port_hashtable[sctp_phashfn(snum)]; + head = &sctp_port_hashtable[sctp_phashfn(snum)]; sctp_spin_lock(&head->lock); for (pp = head->chain; pp; pp = pp->next) { if (pp->port == snum) @@ -2624,12 +3509,12 @@ * used by other socket (pp->sk != NULL); that other * socket is going to be sk2. */ - int sk_reuse = sk->reuse; + int sk_reuse = sk->sk_reuse; struct sock *sk2 = pp->sk; SCTP_DEBUG_PRINTK("sctp_get_port() found a " "possible match\n"); - if (pp->fastreuse != 0 && sk->reuse != 0) + if (pp->fastreuse != 0 && sk->sk_reuse != 0) goto success; /* Run through the list of sockets bound to the port @@ -2646,7 +3531,7 @@ struct sctp_endpoint *ep2; ep2 = sctp_sk(sk2)->ep; - if (sk_reuse && sk2->reuse) + if (sk_reuse && sk2->sk_reuse) continue; if (sctp_bind_addr_match(&ep2->base.bind_addr, addr, @@ -2670,12 +3555,12 @@ goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only - * if sk->reuse is too (that is, if the caller requested + * if sk->sk_reuse is too (that is, if the caller requested * SO_REUSEADDR on this socket -sk-). */ if (!pp->sk) - pp->fastreuse = sk->reuse ? 1 : 0; - else if (pp->fastreuse && sk->reuse == 0) + pp->fastreuse = sk->sk_reuse ? 1 : 0; + else if (pp->fastreuse && sk->sk_reuse == 0) pp->fastreuse = 0; /* We are set, so fill up all the data in the hash table @@ -2717,7 +3602,7 @@ af->from_sk(&addr, sk); addr.v4.sin_port = htons(snum); - /* Note: sk->num gets filled in if ephemeral port request. */ + /* Note: sk->sk_num gets filled in if ephemeral port request. */ ret = sctp_get_port_local(sk, &addr); return (ret ? 1 : 0); @@ -2738,12 +3623,22 @@ /* Only UDP style sockets that are not peeled off are allowed to * listen(). */ - if (SCTP_SOCKET_UDP != sp->type) + if (!sctp_style(sk, UDP)) return -EINVAL; - if (sk->state == SCTP_SS_LISTENING) - return 0; + /* If backlog is zero, disable listening. */ + if (!backlog) { + if (sctp_sstate(sk, CLOSED)) + return 0; + + sctp_unhash_endpoint(ep); + sk->sk_state = SCTP_SS_CLOSED; + } + /* Return if we are already listening. */ + if (sctp_sstate(sk, LISTENING)) + return 0; + /* * If a bind() or sctp_bindx() is not called prior to a listen() * call that allows new associations to be accepted, the system @@ -2758,7 +3653,7 @@ if (sctp_autobind(sk)) return -EAGAIN; } - sk->state = SCTP_SS_LISTENING; + sk->sk_state = SCTP_SS_LISTENING; sctp_hash_endpoint(ep); return 0; } @@ -2774,7 +3669,16 @@ struct sctp_opt *sp = sctp_sk(sk); struct sctp_endpoint *ep = sp->ep; - if (sk->state == SCTP_SS_LISTENING) + /* If backlog is zero, disable listening. */ + if (!backlog) { + if (sctp_sstate(sk, CLOSED)) + return 0; + + sctp_unhash_endpoint(ep); + sk->sk_state = SCTP_SS_CLOSED; + } + + if (sctp_sstate(sk, LISTENING)) return 0; /* @@ -2791,8 +3695,8 @@ if (sctp_autobind(sk)) return -EAGAIN; } - sk->state = SCTP_SS_LISTENING; - sk->max_ack_backlog = backlog; + sk->sk_state = SCTP_SS_LISTENING; + sk->sk_max_ack_backlog = backlog; sctp_hash_endpoint(ep); return 0; } @@ -2863,41 +3767,40 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; + struct sctp_opt *sp = sctp_sk(sk); unsigned int mask; - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); + + /* A TCP-style listening socket becomes readable when the accept queue + * is not empty. + */ + if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) + return (!list_empty(&sp->ep->asocs)) ? + (POLLIN | POLLRDNORM) : 0; + mask = 0; /* Is there any exceptional events? */ - if (sk->err || !skb_queue_empty(&sk->error_queue)) + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; - if (sk->shutdown == SHUTDOWN_MASK) + if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; /* Is it readable? Reconsider this code with TCP-style support. */ - if (!skb_queue_empty(&sk->receive_queue) || - (sk->shutdown & RCV_SHUTDOWN)) + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - /* - * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and - * peeled off sockets. Additionally, TCP-style needs to consider - * other establishment conditions. - */ - if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) { - /* The association is going away. */ - if (SCTP_SS_DISCONNECTING == sk->state) - mask |= POLLHUP; - /* The association is either gone or not ready. */ - if (SCTP_SS_CLOSED == sk->state) - return mask; - } + /* The association is either gone or not ready. */ + if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED)) + return mask; /* Is it writable? */ if (sctp_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); /* * Since the socket is not locked, the buffer * might be made available after the writeable check and @@ -2916,12 +3819,13 @@ * 2nd Level Abstractions ********************************************************************/ -static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) +static struct sctp_bind_bucket *sctp_bucket_create( + struct sctp_bind_hashbucket *head, unsigned short snum) { - sctp_bind_bucket_t *pp; + struct sctp_bind_bucket *pp; SCTP_DEBUG_PRINTK( "sctp_bucket_create() begins, snum=%d\n", snum); - pp = kmalloc(sizeof(sctp_bind_bucket_t), GFP_ATOMIC); + pp = kmalloc(sizeof(struct sctp_bind_bucket), GFP_ATOMIC); if (pp) { pp->port = snum; pp->fastreuse = 0; @@ -2935,16 +3839,15 @@ return pp; } -/* FIXME: Comments! */ +/* Release this socket's reference to a local port. */ static __inline__ void __sctp_put_port(struct sock *sk) { - struct sctp_protocol *sctp_proto = sctp_get_protocol(); - sctp_bind_hashbucket_t *head = - &sctp_proto->port_hashtable[sctp_phashfn((sk)->num)]; - sctp_bind_bucket_t *pp; + struct sctp_bind_hashbucket *head = + &sctp_port_hashtable[sctp_phashfn((sk)->num)]; + struct sctp_bind_bucket *pp; sctp_spin_lock(&head->lock); - pp = (sctp_bind_bucket_t *) sk->prev; + pp = (struct sctp_bind_bucket *) sk->prev; if (sk->bind_next) sk->bind_next->bind_pprev = sk->bind_pprev; *(sk->bind_pprev) = sk->bind_next; @@ -2981,7 +3884,7 @@ /* Initialize a local sockaddr structure to INADDR_ANY. */ af = sctp_sk(sk)->pf->af; - port = htons((sk)->num); + port = htons(sk->num); af->inaddr_any(&autoaddr, port); return sctp_do_bind(sk, &autoaddr, af->sockaddr_len); @@ -3110,19 +4013,19 @@ int error; DECLARE_WAITQUEUE(wait, current); + add_wait_queue_exclusive(sk->sk_sleep, &wait); __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue_exclusive(sk->sleep, &wait); /* Socket errors? */ error = sock_error(sk); if (error) goto out; - if (!skb_queue_empty(&sk->receive_queue)) + if (!skb_queue_empty(&sk->sk_receive_queue)) goto ready; /* Socket shut down? */ - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) goto out; /* Sequenced packets can come disconnected. If so we report the @@ -3131,8 +4034,7 @@ error = -ENOTCONN; /* Is there a good reason to think that we may receive some data? */ - if ((list_empty(&sctp_sk(sk)->ep->asocs)) && - (sk->state != SCTP_SS_LISTENING)) + if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING)) goto out; /* Handle signals. */ @@ -3149,7 +4051,7 @@ sctp_lock_sock(sk); ready: - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); __set_current_state(TASK_RUNNING); return 0; @@ -3157,7 +4059,7 @@ error = sock_intr_errno(*timeo_p); out: - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); __set_current_state(TASK_RUNNING); *err = error; return error; @@ -3174,7 +4076,7 @@ struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before calling. */ + /* Caller is allowed not to check sk->sk_err before calling. */ error = sock_error(sk); if (error) goto no_packet; @@ -3195,21 +4097,21 @@ if (flags & MSG_PEEK) { unsigned long cpu_flags; - sctp_spin_lock_irqsave(&sk->receive_queue.lock, + sctp_spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->receive_queue); + skb = skb_peek(&sk->sk_receive_queue); if (skb) atomic_inc(&skb->users); - sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, + sctp_spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); } else { - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); } if (skb) return skb; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; /* User doesn't want to wait. */ @@ -3237,7 +4139,7 @@ return -EINVAL; /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr)) + if (!af->addr_valid(addr, sctp_sk(sk))) return -EINVAL; if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) @@ -3252,7 +4154,7 @@ struct sock *sk = asoc->base.sk; int amt = 0; - amt = sk->sndbuf - asoc->sndbuf_used; + amt = sk->sk_sndbuf - asoc->sndbuf_used; if (amt < 0) amt = 0; return amt; @@ -3267,7 +4169,7 @@ * destructor in the data chunk skb for the purpose of the sndbuf space * tracking. */ -static inline void sctp_set_owner_w(sctp_chunk_t *chunk) +static inline void sctp_set_owner_w(struct sctp_chunk *chunk) { struct sctp_association *asoc = chunk->asoc; struct sock *sk = asoc->base.sk; @@ -3277,32 +4179,32 @@ chunk->skb->destructor = sctp_wfree; /* Save the chunk pointer in skb for sctp_wfree to use later. */ - *((sctp_chunk_t **)(chunk->skb->cb)) = chunk; + *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); } /* If sndbuf has changed, wake up per association sndbuf waiters. */ static void __sctp_write_space(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; - struct socket *sock = sk->socket; + struct socket *sock = sk->sk_socket; if ((sctp_wspace(asoc) > 0) && sock) { if (waitqueue_active(&asoc->wait)) wake_up_interruptible(&asoc->wait); if (sctp_writeable(sk)) { - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); /* Note that we try to include the Async I/O support * here by modeling from the current TCP/UDP code. * We have not tested with it yet. */ if (sock->fasync_list && - !(sk->shutdown & SEND_SHUTDOWN)) + !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); } } @@ -3315,15 +4217,15 @@ static void sctp_wfree(struct sk_buff *skb) { struct sctp_association *asoc; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sock *sk; /* Get the saved chunk pointer. */ - chunk = *((sctp_chunk_t **)(skb->cb)); + chunk = *((struct sctp_chunk **)(skb->cb)); asoc = chunk->asoc; sk = asoc->base.sk; asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); - sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); __sctp_write_space(asoc); sctp_association_put(asoc); @@ -3331,26 +4233,28 @@ /* Helper function to wait for space in the sndbuf. */ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p, - int msg_len) + size_t msg_len) { struct sock *sk = asoc->base.sk; int err = 0; long current_timeo = *timeo_p; DECLARE_WAITQUEUE(wait, current); - SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n", + SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%u\n", asoc, (long)(*timeo_p), msg_len); - /* Wait on the association specific sndbuf space. */ - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); + + /* Wait on the association specific sndbuf space. */ + add_wait_queue_exclusive(&asoc->wait, &wait); + + /* Wait on the association specific sndbuf space. */ for (;;) { - set_current_state(TASK_INTERRUPTIBLE); + __set_current_state(TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; - if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) @@ -3370,11 +4274,11 @@ out: remove_wait_queue(&asoc->wait, &wait); + __set_current_state(TASK_RUNNING); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); return err; do_error: @@ -3418,7 +4322,7 @@ { int amt = 0; - amt = sk->sndbuf - sk->wmem_queued; + amt = sk->sk_sndbuf - sk->sk_wmem_queued; if (amt < 0) amt = 0; return amt; @@ -3437,24 +4341,23 @@ SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, (long)(*timeo_p)); - add_wait_queue_exclusive(&asoc->wait, &wait); - /* Increment the association's refcnt. */ sctp_association_hold(asoc); + add_wait_queue_exclusive(&asoc->wait, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; - if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) goto do_interrupted; - if (asoc->state == SCTP_STATE_ESTABLISHED) + if (sctp_state(asoc, ESTABLISHED)) break; /* Let another process have a go. Since we are going @@ -3469,12 +4372,11 @@ out: remove_wait_queue(&asoc->wait, &wait); + __set_current_state(TASK_RUNNING); /* Release the association's refcnt. */ sctp_association_put(asoc); - __set_current_state(TASK_RUNNING); - return err; do_error: @@ -3498,7 +4400,7 @@ ep = sctp_sk(sk)->ep; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); @@ -3509,7 +4411,7 @@ } err = -EINVAL; - if (sk->state != SCTP_SS_LISTENING) + if (!sctp_sstate(sk, LISTENING)) break; err = 0; @@ -3525,12 +4427,31 @@ break; } - remove_wait_queue(sk->sleep, &wait); - __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + __set_current_state(TASK_RUNNING); return err; } +void sctp_wait_for_close(struct sock *sk, long timeout) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue_exclusive(sk->sk_sleep, &wait); + + do { + __set_current_state(TASK_INTERRUPTIBLE); + if (list_empty(&sctp_sk(sk)->ep->asocs)) + break; + sctp_release_sock(sk); + timeout = schedule_timeout(timeout); + sctp_lock_sock(sk); + } while (!signal_pending(current) && timeout); + + remove_wait_queue(sk->sk_sleep, &wait); + __set_current_state(TASK_RUNNING); +} + /* Populate the fields of the newsk from the oldsk and migrate the assoc * and its messages to the newsk. */ @@ -3547,9 +4468,10 @@ /* Migrate socket buffer sizes and all the socket level options to the * new socket. */ - newsk->sndbuf = oldsk->sndbuf; - newsk->rcvbuf = oldsk->rcvbuf; - *newsp = *oldsp; + newsk->sk_sndbuf = oldsk->sk_sndbuf; + newsk->sk_rcvbuf = oldsk->sk_rcvbuf; + /* Brute force copy old sctp opt. */ + memcpy(newsp, oldsp, sizeof(struct sctp_opt)); /* Restore the ep value that was overwritten with the above structure * copy. @@ -3557,14 +4479,16 @@ newsp->ep = newep; newsp->hmac = NULL; + newsk->num = oldsk->num; + /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. */ - sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) { + sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); - if (event->event_asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); - __skb_queue_tail(&newsk->receive_queue, skb); + __skb_queue_tail(&newsk->sk_receive_queue, skb); } } @@ -3584,14 +4508,14 @@ if (assoc->ulpq.pd_mode) { queue = &newsp->pd_lobby; } else - queue = &newsk->receive_queue; + queue = &newsk->sk_receive_queue; /* Walk through the pd_lobby, looking for skbs that * need moved to the new socket. */ sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { event = sctp_skb2event(skb); - if (event->event_asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(queue, skb); } @@ -3614,7 +4538,13 @@ /* Migrate the association to the new socket. */ sctp_assoc_migrate(assoc, newsk); - newsk->state = SCTP_SS_ESTABLISHED; + /* If the association on the newsk is already closed before accept() + * is called, set RCV_SHUTDOWN flag. + */ + if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) + newsk->sk_shutdown |= RCV_SHUTDOWN; + + newsk->sk_state = SCTP_SS_ESTABLISHED; } /* This proto struct describes the ULP interface for SCTP. */ diff -urN linux-2.4.25/net/sctp/ssnmap.c linux-2.4.26/net/sctp/ssnmap.c --- linux-2.4.25/net/sctp/ssnmap.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/ssnmap.c 2004-04-14 06:05:41.000000000 -0700 @@ -40,6 +40,7 @@ #include #include +#define MAX_KMALLOC_SIZE 131072 /* Storage size needed for map includes 2 headers and then the * specific needs of in or out streams. @@ -56,9 +57,14 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp) { struct sctp_ssnmap *retval; + int size; - retval = kmalloc(sctp_ssnmap_size(in, out), gfp); - + size = sctp_ssnmap_size(in, out); + if (size <= MAX_KMALLOC_SIZE) + retval = kmalloc(size, gfp); + else + retval = (struct sctp_ssnmap *) + __get_free_pages(gfp, get_order(size)); if (!retval) goto fail; @@ -71,7 +77,10 @@ return retval; fail_map: - kfree(retval); + if (size <= MAX_KMALLOC_SIZE) + kfree(retval); + else + free_pages((unsigned long)retval, get_order(size)); fail: return NULL; } @@ -107,7 +116,13 @@ void sctp_ssnmap_free(struct sctp_ssnmap *map) { if (map && map->malloced) { - kfree(map); + int size; + + size = sctp_ssnmap_size(map->in.len, map->out.len); + if (size <= MAX_KMALLOC_SIZE) + kfree(map); + else + free_pages((unsigned long)map, get_order(size)); SCTP_DBG_OBJCNT_DEC(ssnmap); } } diff -urN linux-2.4.25/net/sctp/sysctl.c linux-2.4.26/net/sctp/sysctl.c --- linux-2.4.25/net/sctp/sysctl.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/sysctl.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,39 +1,40 @@ -/* SCTP kernel reference Implementation +/* SCTP kernel reference Implementation * Copyright (c) 2002 International Business Machines Corp. * Copyright (c) 2002 Intel Corp. - * + * * This file is part of the SCTP kernel reference Implementation - * - * Sysctl related interfaces for SCTP. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * + * Sysctl related interfaces for SCTP. + * + * The SCTP reference implementation 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. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation 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 GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * Mingqin Liu * Jon Grimm * Ardelle Fan + * Ryan Layer * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -42,49 +43,59 @@ #include #include -extern struct sctp_protocol sctp_proto; +static ctl_handler sctp_sysctl_jiffies_ms; +static long rto_timer_min = 1; +static long rto_timer_max = 86400000; /* One day */ static ctl_table sctp_table[] = { { .ctl_name = NET_SCTP_RTO_INITIAL, .procname = "rto_initial", - .data = &sctp_proto.rto_initial, - .maxlen = sizeof(int), + .data = &sctp_rto_initial, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_RTO_MIN, .procname = "rto_min", - .data = &sctp_proto.rto_min, - .maxlen = sizeof(int), + .data = &sctp_rto_min, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_RTO_MAX, .procname = "rto_max", - .data = &sctp_proto.rto_max, - .maxlen = sizeof(int), + .data = &sctp_rto_max, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_VALID_COOKIE_LIFE, .procname = "valid_cookie_life", - .data = &sctp_proto.valid_cookie_life, - .maxlen = sizeof(int), + .data = &sctp_valid_cookie_life, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_MAX_BURST, .procname = "max_burst", - .data = &sctp_proto.max_burst, + .data = &sctp_max_burst, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -92,7 +103,7 @@ { .ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS, .procname = "association_max_retrans", - .data = &sctp_proto.max_retrans_association, + .data = &sctp_max_retrans_association, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -100,7 +111,7 @@ { .ctl_name = NET_SCTP_PATH_MAX_RETRANS, .procname = "path_max_retrans", - .data = &sctp_proto.max_retrans_path, + .data = &sctp_max_retrans_path, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -108,7 +119,7 @@ { .ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS, .procname = "max_init_retransmits", - .data = &sctp_proto.max_retrans_init, + .data = &sctp_max_retrans_init, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -116,25 +127,29 @@ { .ctl_name = NET_SCTP_HB_INTERVAL, .procname = "hb_interval", - .data = &sctp_proto.hb_interval, - .maxlen = sizeof(int), + .data = &sctp_hb_interval, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_PRESERVE_ENABLE, .procname = "cookie_preserve_enable", - .data = &sctp_proto.cookie_preserve_enable, - .maxlen = sizeof(int), + .data = &sctp_cookie_preserve_enable, + .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &rto_timer_min, + .extra2 = &rto_timer_max }, { .ctl_name = NET_SCTP_RTO_ALPHA, .procname = "rto_alpha_exp_divisor", - .data = &sctp_proto.rto_alpha, + .data = &sctp_rto_alpha, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -142,7 +157,15 @@ { .ctl_name = NET_SCTP_RTO_BETA, .procname = "rto_beta_exp_divisor", - .data = &sctp_proto.rto_beta, + .data = &sctp_rto_beta, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_SCTP_ADDIP_ENABLE, + .procname = "addip_enable", + .data = &sctp_addip_enable, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -154,7 +177,6 @@ { .ctl_name = NET_SCTP, .procname = "sctp", - .maxlen = 0, .mode = 0555, .child = sctp_table }, @@ -165,7 +187,6 @@ { .ctl_name = CTL_NET, .procname = "net", - .maxlen = 0, .mode = 0555, .child = sctp_net_table }, @@ -185,3 +206,37 @@ { unregister_sysctl_table(sctp_sysctl_header); } + +/* Strategy function to convert jiffies to milliseconds. */ +static int sctp_sysctl_jiffies_ms(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + if (oldval) { + size_t olen; + + if (oldlenp) { + if (get_user(olen, oldlenp)) + return -EFAULT; + + if (olen != sizeof (int)) + return -EINVAL; + } + if (put_user((*(int *)(table->data) * 1000) / HZ, + (int *)oldval) || + (oldlenp && put_user(sizeof (int), oldlenp))) + return -EFAULT; + } + if (newval && newlen) { + int new; + + if (newlen != sizeof (int)) + return -EINVAL; + + if (get_user(new, (int *)newval)) + return -EFAULT; + + *(int *)(table->data) = (new * HZ) / 1000; + } + return 1; +} diff -urN linux-2.4.25/net/sctp/transport.c linux-2.4.26/net/sctp/transport.c --- linux-2.4.25/net/sctp/transport.c 2004-02-18 05:36:32.000000000 -0800 +++ linux-2.4.26/net/sctp/transport.c 2004-04-14 06:05:41.000000000 -0700 @@ -83,8 +83,6 @@ const union sctp_addr *addr, int gfp) { - struct sctp_protocol *proto = sctp_get_protocol(); - /* Copy in the address. */ peer->ipaddr = *addr; peer->af_specific = sctp_get_af_specific(addr->sa.sa_family); @@ -100,7 +98,7 @@ * parameter 'RTO.Initial'. */ peer->rtt = 0; - peer->rto = proto->rto_initial; + peer->rto = sctp_rto_initial; peer->rttvar = 0; peer->srtt = 0; peer->rto_pending = 0; @@ -109,19 +107,18 @@ peer->last_time_used = jiffies; peer->last_time_ecne_reduced = jiffies; - peer->active = 1; + peer->active = SCTP_ACTIVE; peer->hb_allowed = 0; /* Initialize the default path max_retrans. */ - peer->max_retrans = proto->max_retrans_path; + peer->max_retrans = sctp_max_retrans_path; peer->error_threshold = 0; peer->error_count = 0; - peer->debug_name = "unnamedtransport"; - INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->send_ready); INIT_LIST_HEAD(&peer->transports); + sctp_packet_init(&peer->packet, peer, 0, 0); /* Set up the retransmission timer. */ init_timer(&peer->T3_rtx_timer); @@ -138,6 +135,13 @@ peer->dead = 0; peer->malloced = 0; + + /* Initialize the state information for SFR-CACC */ + peer->cacc.changeover_active = 0; + peer->cacc.cycling_changeover = 0; + peer->cacc.next_tsn_at_change = 0; + peer->cacc.cacc_saw_newack = 0; + return peer; } @@ -241,7 +245,7 @@ if (dst) { transport->pmtu = dst_pmtu(dst); - /* Initialize sk->rcv_saddr, if the transport is the + /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). */ if (asoc && (transport == asoc->peer.active_path)) @@ -268,8 +272,6 @@ /* Update transport's RTO based on the newly calculated RTT. */ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) { - struct sctp_protocol *proto = sctp_get_protocol(); - /* Check for valid transport. */ SCTP_ASSERT(tp, "NULL transport", return); @@ -288,10 +290,10 @@ * For example, assuming the default value of RTO.Alpha of * 1/8, rto_alpha would be expressed as 3. */ - tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) - + ((abs(tp->srtt - rtt)) >> proto->rto_beta); - tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) - + (rtt >> proto->rto_alpha); + tp->rttvar = tp->rttvar - (tp->rttvar >> sctp_rto_beta) + + ((abs(tp->srtt - rtt)) >> sctp_rto_beta); + tp->srtt = tp->srtt - (tp->srtt >> sctp_rto_alpha) + + (rtt >> sctp_rto_alpha); } else { /* 6.3.1 C2) When the first RTT measurement R is made, set * SRTT <- R, RTTVAR <- R/2. diff -urN linux-2.4.25/net/sctp/tsnmap.c linux-2.4.26/net/sctp/tsnmap.c --- linux-2.4.25/net/sctp/tsnmap.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/tsnmap.c 2004-04-14 06:05:41.000000000 -0700 @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. + * Copyright (c) 2001-2003 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * * This file is part of the SCTP kernel reference Implementation @@ -46,7 +46,6 @@ #include static void sctp_tsnmap_update(struct sctp_tsnmap *map); -static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map); static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off, __u16 len, __u16 base, int *started, __u16 *start, @@ -92,7 +91,6 @@ map->cumulative_tsn_ack_point = initial_tsn - 1; map->max_tsn_seen = map->cumulative_tsn_ack_point; map->malloced = 0; - map->pending_data = 0; map->num_dup_tsns = 0; return map; @@ -135,14 +133,6 @@ return dup; } -/* Is there a gap in the TSN map? */ -int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map) -{ - int has_gap; - - has_gap = (map->cumulative_tsn_ack_point != map->max_tsn_seen); - return has_gap; -} /* Mark this TSN as seen. */ void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn) @@ -176,21 +166,6 @@ sctp_tsnmap_update(map); } -void sctp_tsnmap_report_dup(struct sctp_tsnmap *map, __u32 tsn) -{ -} - -/* Retrieve the Cumulative TSN Ack Point. */ -__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map) -{ - return map->cumulative_tsn_ack_point; -} - -/* Retrieve the highest TSN we've seen. */ -__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map) -{ - return map->max_tsn_seen; -} /* Dispose of a tsnmap. */ void sctp_tsnmap_free(struct sctp_tsnmap *map) @@ -219,6 +194,10 @@ /* We haven't found a gap yet. */ started = ended = 0; + /* If there are no more gap acks possible, get out fast. */ + if (TSN_lte(map->max_tsn_seen, iter->start)) + return 0; + /* Search the first mapping array. */ if (iter->start - map->base_tsn < map->len) { @@ -304,10 +283,11 @@ } while (map->tsn_map[ctsn - map->base_tsn]); map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */ - sctp_tsnmap_update_pending_data(map); } -static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map) +/* How many data chunks are we missing from our peer? + */ +__u16 sctp_tsnmap_pending(struct sctp_tsnmap *map) { __u32 cum_tsn = map->cumulative_tsn_ack_point; __u32 max_tsn = map->max_tsn_seen; @@ -339,7 +319,7 @@ } out: - map->pending_data = pending_data; + return pending_data; } /* This is a private helper for finding Gap Ack Blocks. It searches a @@ -359,6 +339,8 @@ * early if we have found the end of the Gap Ack Block. */ + /* Also, stop looking past the maximum TSN seen. */ + /* Look for the start. */ if (!(*started)) { for (; i < len; i++) { @@ -404,3 +386,26 @@ else map->overflow_map[gap - map->len] = 0; } + +/* How many gap ack blocks do we have recorded? */ +__u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map) +{ + struct sctp_tsnmap_iter iter; + int gabs = 0; + + /* Refresh the gap ack information. */ + if (sctp_tsnmap_has_gap(map)) { + sctp_tsnmap_iter_init(map, &iter); + while (sctp_tsnmap_next_gap_ack(map, &iter, + &map->gabs[gabs].start, + &map->gabs[gabs].end)) { + + map->gabs[gabs].start = htons(map->gabs[gabs].start); + map->gabs[gabs].end = htons(map->gabs[gabs].end); + gabs++; + if (gabs >= SCTP_MAX_GABS) + break; + } + } + return gabs; +} diff -urN linux-2.4.25/net/sctp/ulpevent.c linux-2.4.26/net/sctp/ulpevent.c --- linux-2.4.25/net/sctp/ulpevent.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/ulpevent.c 2004-04-14 06:05:41.000000000 -0700 @@ -35,6 +35,8 @@ * Written or modified by: * Jon Grimm * La Monte H.P. Yarroll + * Ardelle Fan + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -46,10 +48,12 @@ #include #include -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc); -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc); +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc); +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc); +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) @@ -62,30 +66,19 @@ goto fail; event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, msg_flags); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, msg_flags); + return event; -fail_init: - kfree_skb(skb); fail: return NULL; } /* Initialize an ULP event from an given skb. */ -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *event, - int msg_flags) +void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) { memset(event, sizeof(struct sctp_ulpevent), 0x00); event->msg_flags = msg_flags; - return event; -} - -/* Dispose of an event. */ -void sctp_ulpevent_free(struct sctp_ulpevent *event) -{ - kfree_skb(sctp_event2skb(event)); } /* Is this a MSG_NOTIFICATION? */ @@ -189,7 +182,7 @@ * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sac->sac_assoc_id = sctp_assoc2id(asoc); return event; @@ -281,7 +274,7 @@ * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); spc->spc_assoc_id = sctp_assoc2id(asoc); /* Sockets API Extensions for SCTP @@ -294,6 +287,11 @@ */ memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map( + sctp_sk(asoc->base.sk), + (union sctp_addr *)&spc->spc_aaddr); + return event; fail: @@ -316,7 +314,7 @@ * error formats. */ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( - const struct sctp_association *asoc, sctp_chunk_t *chunk, + const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, int gfp) { struct sctp_ulpevent *event; @@ -328,7 +326,7 @@ ch = (sctp_errhdr_t *)(chunk->skb->data); cause = ch->cause; - elen = ntohs(ch->length) - sizeof(sctp_errhdr_t); + elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t); /* Pull off the ERROR header. */ skb_pull(chunk->skb, sizeof(sctp_errhdr_t)); @@ -336,10 +334,8 @@ /* Copy the skb to a new skb with room for us to prepend * notification with. */ - skb = skb_copy_expand(chunk->skb, - sizeof(struct sctp_remote_error), /* headroom */ - 0, /* tailroom */ - gfp); + skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), + 0, gfp); /* Pull off the rest of the cause TLV from the chunk. */ skb_pull(chunk->skb, elen); @@ -348,10 +344,7 @@ /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); sre = (struct sctp_remote_error *) skb_push(skb, sizeof(struct sctp_remote_error)); @@ -404,8 +397,7 @@ * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sre->sre_assoc_id = sctp_assoc2id(asoc); return event; @@ -420,13 +412,16 @@ * 5.3.1.4 SCTP_SEND_FAILED */ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( - const struct sctp_association *asoc, sctp_chunk_t *chunk, + const struct sctp_association *asoc, struct sctp_chunk *chunk, __u16 flags, __u32 error, int gfp) { struct sctp_ulpevent *event; struct sctp_send_failed *ssf; struct sk_buff *skb; + /* Pull off any padding. */ + int len = ntohs(chunk->chunk_hdr->length); + /* Make skb with more room so we can prepend notification. */ skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_send_failed), /* headroom */ @@ -436,13 +431,12 @@ goto fail; /* Pull off the common chunk header and DATA header. */ - skb_pull(skb, sizeof(sctp_data_chunk_t)); + skb_pull(skb, sizeof(struct sctp_data_chunk)); + len -= sizeof(struct sctp_data_chunk); /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); @@ -477,7 +471,8 @@ * This field is the total length of the notification data, including * the notification header. */ - ssf->ssf_length = skb->len; + ssf->ssf_length = sizeof(struct sctp_send_failed) + len; + skb_trim(skb, ssf->ssf_length); /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED @@ -498,6 +493,11 @@ */ memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); + /* Per TSVWG discussion with Randy. Allow the application to + * ressemble a fragmented message. + */ + ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; + /* Socket Extensions for SCTP * 5.3.1.4 SCTP_SEND_FAILED * @@ -507,8 +507,7 @@ * same association identifier. For TCP style socket, this field is * ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc); return event; @@ -571,7 +570,7 @@ * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sse->sse_assoc_id = sctp_assoc2id(asoc); return event; @@ -588,11 +587,12 @@ * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) */ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, - sctp_chunk_t *chunk, int gfp) + struct sctp_chunk *chunk, + int gfp) { struct sctp_ulpevent *event; struct sctp_sndrcvinfo *info; - struct sk_buff *skb, *list; + struct sk_buff *skb; size_t padding, len; /* Clone the original skb, sharing the data. */ @@ -618,24 +618,15 @@ /* Fixup cloned skb with just this chunks data. */ skb_trim(skb, chunk->chunk_end - padding - skb->data); - /* Set up a destructor to do rwnd accounting. */ - sctp_ulpevent_set_owner_r(skb, asoc); - /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); /* Initialize event with flags 0. */ - event = sctp_ulpevent_init(event, 0); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, 0); event->iif = sctp_chunk_iif(chunk); - /* Note: Not clearing the entire event struct as - * this is just a fragment of the real event. However, - * we still need to do rwnd accounting. - */ - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) - sctp_ulpevent_set_owner_r(list, asoc); + + sctp_ulpevent_receive_data(event, asoc); info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; @@ -672,7 +663,7 @@ * for and this information is passed opaquely by the SCTP stack from * one end to the other. */ - info->sinfo_ppid = ntohl(chunk->subh.data_hdr->ppid); + info->sinfo_ppid = chunk->subh.data_hdr->ppid; /* Sockets API Extensions for SCTP * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) @@ -726,9 +717,6 @@ return event; -fail_init: - kfree_skb(skb); - fail: return NULL; } @@ -745,7 +733,7 @@ const struct sctp_association *asoc, __u32 indication, int gfp) { struct sctp_ulpevent *event; - struct sctp_rcv_pdapi_event *pd; + struct sctp_pdapi_event *pd; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), @@ -754,8 +742,8 @@ goto fail; skb = sctp_event2skb(event); - pd = (struct sctp_rcv_pdapi_event *) - skb_put(skb, sizeof(struct sctp_rcv_pdapi_event)); + pd = (struct sctp_pdapi_event *) + skb_put(skb, sizeof(struct sctp_pdapi_event)); /* pdapi_type * It should be SCTP_PARTIAL_DELIVERY_EVENT @@ -770,9 +758,9 @@ * * This field is the total length of the notification data, including * the notification header. It will generally be sizeof (struct - * sctp_rcv_pdapi_event). + * sctp_pdapi_event). */ - pd->pdapi_length = sizeof(struct sctp_rcv_pdapi_event); + pd->pdapi_length = sizeof(struct sctp_pdapi_event); /* pdapi_indication: 32 bits (unsigned integer) * @@ -784,6 +772,7 @@ * * The association id field, holds the identifier for the association. */ + sctp_ulpevent_set_owner(event, asoc); pd->pdapi_assoc_id = sctp_assoc2id(asoc); return event; @@ -801,7 +790,7 @@ skb = sctp_event2skb((struct sctp_ulpevent *)event); notification = (union sctp_notification *) skb->data; - return notification->h.sn_type; + return notification->sn_header.sn_type; } /* Copy out the sndrcvinfo into a msghdr. */ @@ -815,69 +804,115 @@ } } -/* Do accounting for bytes just read by user. */ -static void sctp_rcvmsg_rfree(struct sk_buff *skb) +/* Stub skb destructor. */ +static void sctp_stub_rfree(struct sk_buff *skb) { - struct sctp_association *asoc; - struct sctp_ulpevent *event; - - /* Current stack structures assume that the rcv buffer is - * per socket. For UDP style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * Use the local private area of the skb to track the owning - * association. - */ - event = sctp_skb2event(skb); - asoc = event->event_asoc; - sctp_assoc_rwnd_increase(asoc, skb_headlen(skb)); - sctp_association_put(asoc); +/* WARNING: This function is just a warning not to use the + * skb destructor. If the skb is shared, we may get the destructor + * callback on some processor that does not own the sock_lock. This + * was occuring with PACKET socket applications that were monitoring + * our skbs. We can't take the sock_lock, because we can't risk + * recursing if we do really own the sock lock. Instead, do all + * of our rwnd manipulation while we own the sock_lock outright. + */ } -/* Charge receive window for bytes received. */ -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc) +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) { - struct sctp_ulpevent *event; + struct sk_buff *skb; - /* The current stack structures assume that the rcv buffer is - * per socket. For UDP-style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * We use the local private area of the skb to track the owning - * association. + /* Cast away the const, as we are just wanting to + * bump the reference count. */ - sctp_association_hold(asoc); + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->event_asoc = asoc; + event->sndrcvinfo.sinfo_assoc_id = sctp_assoc2id(asoc); + skb->destructor = sctp_stub_rfree; +} + +/* A simple destructor to give up the reference to the association. */ +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) +{ + sctp_association_put(event->sndrcvinfo.sinfo_assoc_id); +} - skb->destructor = sctp_rcvmsg_rfree; +/* Do accounting for bytes received and hold a reference to the association + * for each skb. + */ +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc) +{ + struct sk_buff *skb, *frag; + skb = sctp_event2skb(event); + /* Set the owner and charge rwnd for bytes received. */ + sctp_ulpevent_set_owner(event, asoc); sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); + + /* Note: Not clearing the entire event struct as this is just a + * fragment of the real event. However, we still need to do rwnd + * accounting. + * In general, the skb passed from IP can have only 1 level of + * fragments. But we allow multiple levels of fragments. + */ + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); + } } -/* A simple destructor to give up the reference to the association. */ -static void sctp_ulpevent_rfree(struct sk_buff *skb) +/* Do accounting for bytes just read by user and release the references to + * the association. + */ +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; + struct sk_buff *skb, *frag; - event = sctp_skb2event(skb); - sctp_association_put(event->event_asoc); + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * Use the local private area of the skb to track the owning + * association. + */ + + skb = sctp_event2skb(event); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + skb_headlen(skb)); + + /* Don't forget the fragments. */ + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + /* NOTE: skb_shinfos are recursive. Although IP returns + * skb's with only 1 level of fragments, SCTP reassembly can + * increase the levels. + */ + sctp_ulpevent_release_data(sctp_skb2event(frag)); + } + sctp_ulpevent_release_owner(event); } -/* Hold the association in case the msg_name needs read out of - * the association. +/* Free a ulpevent that has an owner. It includes releasing the reference + * to the owner, updating the rwnd in case of a DATA event and freeing the + * skb. + * See comments in sctp_stub_rfree(). */ -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc) +void sctp_ulpevent_free(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; + if (sctp_ulpevent_is_notification(event)) + sctp_ulpevent_release_owner(event); + else + sctp_ulpevent_release_data(event); - /* Cast away the const, as we are just wanting to - * bump the reference count. - */ - sctp_association_hold((struct sctp_association *)asoc); - skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->event_asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_ulpevent_rfree; + kfree_skb(sctp_event2skb(event)); +} + +/* Purge the skb lists holding ulpevents. */ +void sctp_queue_purge_ulpevents(struct sk_buff_head *list) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(list)) != NULL) + sctp_ulpevent_free(sctp_skb2event(skb)); } diff -urN linux-2.4.25/net/sctp/ulpqueue.c linux-2.4.26/net/sctp/ulpqueue.c --- linux-2.4.25/net/sctp/ulpqueue.c 2003-11-28 10:26:21.000000000 -0800 +++ linux-2.4.26/net/sctp/ulpqueue.c 2004-04-14 06:05:41.000000000 -0700 @@ -118,7 +118,7 @@ } /* Process an incoming DATA chunk. */ -int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk, +int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk, int gfp) { struct sk_buff_head temp; @@ -163,7 +163,7 @@ sp->pd_mode = 0; if (!skb_queue_empty(&sp->pd_lobby)) { struct list_head *list; - sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue); + sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue); list = (struct list_head *)&sctp_sk(sk)->pd_lobby; INIT_LIST_HEAD(list); return 1; @@ -189,7 +189,7 @@ /* If the socket is just going to throw this away, do not * even try to deliver it. */ - if ((sk->dead) || (sk->shutdown & RCV_SHUTDOWN)) + if (sk->dead || (sk->sk_shutdown & RCV_SHUTDOWN)) goto out_free; /* Check if the user wishes to receive this event. */ @@ -202,13 +202,13 @@ */ if (!sctp_sk(sk)->pd_mode) { - queue = &sk->receive_queue; + queue = &sk->sk_receive_queue; } else if (ulpq->pd_mode) { if (event->msg_flags & MSG_NOTIFICATION) queue = &sctp_sk(sk)->pd_lobby; else { clear_pd = event->msg_flags & MSG_EOR; - queue = &sk->receive_queue; + queue = &sk->sk_receive_queue; } } else queue = &sctp_sk(sk)->pd_lobby; @@ -229,15 +229,15 @@ if (clear_pd) sctp_ulpq_clear_pd(ulpq); - if (queue == &sk->receive_queue) - sk->data_ready(sk, 0); + if (queue == &sk->sk_receive_queue) + sk->sk_data_ready(sk, 0); return 1; out_free: if (sctp_event2skb(event)->list) - skb_queue_purge(sctp_event2skb(event)->list); + sctp_queue_purge_ulpevents(sctp_event2skb(event)->list); else - kfree_skb(sctp_event2skb(event)); + sctp_ulpevent_free(event); return 0; } @@ -289,7 +289,7 @@ * payload was fragmented on the way and ip had to reassemble them. * We add the rest of skb's to the first skb's fraglist. */ -static inline struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) +static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; struct sctp_ulpevent *event; @@ -325,11 +325,10 @@ /* Remove the fragment from the reassembly queue. */ __skb_unlink(pos, pos->list); - + /* Break if we have reached the last fragment. */ if (pos == l_frag) break; - pos->next = pnext; pos = pnext; }; @@ -570,7 +569,7 @@ /* We are holding the chunks by stream, by SSN. */ sctp_skb_for_each(pos, &ulpq->lobby, tmp) { - cevent = sctp_skb2event(pos); + cevent = (struct sctp_ulpevent *) pos->cb; csid = cevent->sndrcvinfo.sinfo_stream; cssn = cevent->sndrcvinfo.sinfo_ssn; @@ -613,7 +612,7 @@ sid = event->sndrcvinfo.sinfo_stream; ssn = event->sndrcvinfo.sinfo_ssn; - cevent = sctp_skb2event(pos); + cevent = (struct sctp_ulpevent *) pos->cb; csid = cevent->sndrcvinfo.sinfo_stream; cssn = cevent->sndrcvinfo.sinfo_ssn; if (sid > csid) { @@ -630,7 +629,7 @@ * stream ID and then by SSN. */ skb_queue_walk(&ulpq->lobby, pos) { - cevent = sctp_skb2event(pos); + cevent = (struct sctp_ulpevent *) pos->cb; csid = cevent->sndrcvinfo.sinfo_stream; cssn = cevent->sndrcvinfo.sinfo_ssn; @@ -773,7 +772,7 @@ freed = 0; - if (skb_queue_empty(&asoc->base.sk->receive_queue)) { + if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { freed = sctp_ulpq_renege_order(ulpq, needed); if (freed < needed) { freed += sctp_ulpq_renege_frags(ulpq, needed - freed); @@ -812,9 +811,9 @@ SCTP_PARTIAL_DELIVERY_ABORTED, gfp); if (ev) - __skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev)); + __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); /* If there is data waiting, send it up the socket now. */ if (sctp_ulpq_clear_pd(ulpq) || ev) - sk->data_ready(sk, 0); + sk->sk_data_ready(sk, 0); }